Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / video / video_send_stream.cc
index a7eebef..6597029 100644 (file)
 
 #include "webrtc/video/video_send_stream.h"
 
+#include <algorithm>
+#include <sstream>
 #include <string>
 #include <vector>
 
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_capture.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_send_stream.h"
 
 namespace webrtc {
-namespace internal {
+std::string
+VideoSendStream::Config::EncoderSettings::ToString() const {
+  std::stringstream ss;
+  ss << "{payload_name: " << payload_name;
+  ss << ", payload_type: " << payload_type;
+  if (encoder != NULL)
+    ss << ", encoder: " << (encoder != NULL ? "(encoder)" : "NULL");
+  ss << '}';
+  return ss.str();
+}
+
+std::string VideoSendStream::Config::Rtp::Rtx::ToString()
+    const {
+  std::stringstream ss;
+  ss << "{ssrcs: {";
+  for (size_t i = 0; i < ssrcs.size(); ++i) {
+    ss << ssrcs[i];
+    if (i != ssrcs.size() - 1)
+      ss << "}, {";
+  }
+  ss << '}';
+
+  ss << ", payload_type: " << payload_type;
+  ss << '}';
+  return ss.str();
+}
+
+std::string VideoSendStream::Config::Rtp::ToString() const {
+  std::stringstream ss;
+  ss << "{ssrcs: {";
+  for (size_t i = 0; i < ssrcs.size(); ++i) {
+    ss << ssrcs[i];
+    if (i != ssrcs.size() - 1)
+      ss << "}, {";
+  }
+  ss << '}';
+
+  ss << ", max_packet_size: " << max_packet_size;
+  if (min_transmit_bitrate_bps != 0)
+    ss << ", min_transmit_bitrate_bps: " << min_transmit_bitrate_bps;
 
-VideoSendStream::VideoSendStream(newapi::Transport* transport,
-                                 CpuOveruseObserver* overuse_observer,
-                                 webrtc::VideoEngine* video_engine,
-                                 const VideoSendStream::Config& config,
-                                 int base_channel)
+  ss << ", extensions: {";
+  for (size_t i = 0; i < extensions.size(); ++i) {
+    ss << extensions[i].ToString();
+    if (i != extensions.size() - 1)
+      ss << "}, {";
+  }
+  ss << '}';
+
+  if (nack.rtp_history_ms != 0)
+    ss << ", nack.rtp_history_ms: " << nack.rtp_history_ms;
+  if (fec.ulpfec_payload_type != -1 || fec.red_payload_type != -1)
+    ss << ", fec: " << fec.ToString();
+  if (rtx.payload_type != 0 || !rtx.ssrcs.empty())
+    ss << ", rtx: " << rtx.ToString();
+  if (c_name != "")
+    ss << ", c_name: " << c_name;
+  ss << '}';
+  return ss.str();
+}
+
+std::string VideoSendStream::Config::ToString() const {
+  std::stringstream ss;
+  ss << "{encoder_settings: " << encoder_settings.ToString();
+  ss << ", rtp: " << rtp.ToString();
+  if (pre_encode_callback != NULL)
+    ss << ", (pre_encode_callback)";
+  if (post_encode_callback != NULL)
+    ss << ", (post_encode_callback)";
+  if (local_renderer != NULL) {
+    ss << ", (local_renderer, render_delay_ms: " << render_delay_ms << ")";
+  }
+  if (target_delay_ms > 0)
+    ss << ", target_delay_ms: " << target_delay_ms;
+  if (suspend_below_min_bitrate)
+    ss << ", suspend_below_min_bitrate: on";
+  ss << '}';
+  return ss.str();
+}
+
+namespace internal {
+VideoSendStream::VideoSendStream(
+    newapi::Transport* transport,
+    CpuOveruseObserver* overuse_observer,
+    webrtc::VideoEngine* video_engine,
+    const VideoSendStream::Config& config,
+    const std::vector<VideoStream> video_streams,
+    const void* encoder_settings,
+    const std::map<uint32_t, RtpState>& suspended_ssrcs,
+    int base_channel,
+    int start_bitrate_bps)
     : transport_adapter_(transport),
       encoded_frame_proxy_(config.post_encode_callback),
-      codec_lock_(CriticalSectionWrapper::CreateCriticalSection()),
       config_(config),
+      start_bitrate_bps_(start_bitrate_bps),
+      suspended_ssrcs_(suspended_ssrcs),
       external_codec_(NULL),
-      channel_(-1) {
+      channel_(-1),
+      stats_proxy_(config) {
   video_engine_base_ = ViEBase::GetInterface(video_engine);
   video_engine_base_->CreateChannel(channel_, base_channel);
   assert(channel_ != -1);
+  assert(start_bitrate_bps_ > 0);
 
   rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
   assert(rtp_rtcp_ != NULL);
 
   assert(config_.rtp.ssrcs.size() > 0);
-  if (config_.suspend_below_min_bitrate)
-    config_.pacing = true;
-  rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing);
 
   assert(config_.rtp.min_transmit_bitrate_bps >= 0);
   rtp_rtcp_->SetMinTransmitBitrate(channel_,
@@ -90,6 +177,8 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
     rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
   }
 
+  ConfigureSsrcs();
+
   char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength];
   assert(config_.rtp.c_name.length() < ViERTP_RTCP::KMaxRTCPCNameLength);
   strncpy(rtcp_cname, config_.rtp.c_name.c_str(), sizeof(rtcp_cname) - 1);
@@ -122,14 +211,14 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
   }
 
   codec_ = ViECodec::GetInterface(video_engine);
-  if (!ReconfigureVideoEncoder(config_.encoder_settings.streams,
-                               config_.encoder_settings.encoder_settings)) {
+  if (!ReconfigureVideoEncoder(video_streams, encoder_settings))
     abort();
-  }
 
   if (overuse_observer)
     video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer);
 
+  video_engine_base_->RegisterSendSideDelayObserver(channel_, &stats_proxy_);
+
   image_process_ = ViEImageProcess::GetInterface(video_engine);
   image_process_->RegisterPreEncodeCallback(channel_,
                                             config_.pre_encode_callback);
@@ -138,33 +227,30 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
                                                     &encoded_frame_proxy_);
   }
 
-  if (config_.suspend_below_min_bitrate) {
+  if (config_.suspend_below_min_bitrate)
     codec_->SuspendBelowMinBitrate(channel_);
-  }
-
-  stats_proxy_.reset(new SendStatisticsProxy(config, this));
 
   rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(channel_,
-                                                       stats_proxy_.get());
+                                                       &stats_proxy_);
   rtp_rtcp_->RegisterSendChannelRtpStatisticsCallback(channel_,
-                                                      stats_proxy_.get());
-  rtp_rtcp_->RegisterSendBitrateObserver(channel_, stats_proxy_.get());
-  rtp_rtcp_->RegisterSendFrameCountObserver(channel_, stats_proxy_.get());
+                                                      &stats_proxy_);
+  rtp_rtcp_->RegisterSendBitrateObserver(channel_, &stats_proxy_);
+  rtp_rtcp_->RegisterSendFrameCountObserver(channel_, &stats_proxy_);
 
-  codec_->RegisterEncoderObserver(channel_, *stats_proxy_);
-  capture_->RegisterObserver(capture_id_, *stats_proxy_);
+  codec_->RegisterEncoderObserver(channel_, stats_proxy_);
+  capture_->RegisterObserver(capture_id_, stats_proxy_);
 }
 
 VideoSendStream::~VideoSendStream() {
   capture_->DeregisterObserver(capture_id_);
   codec_->DeregisterEncoderObserver(channel_);
 
-  rtp_rtcp_->DeregisterSendFrameCountObserver(channel_, stats_proxy_.get());
-  rtp_rtcp_->DeregisterSendBitrateObserver(channel_, stats_proxy_.get());
+  rtp_rtcp_->DeregisterSendFrameCountObserver(channel_, &stats_proxy_);
+  rtp_rtcp_->DeregisterSendBitrateObserver(channel_, &stats_proxy_);
   rtp_rtcp_->DeregisterSendChannelRtpStatisticsCallback(channel_,
-                                                        stats_proxy_.get());
+                                                        &stats_proxy_);
   rtp_rtcp_->DeregisterSendChannelRtcpStatisticsCallback(channel_,
-                                                         stats_proxy_.get());
+                                                         &stats_proxy_);
 
   image_process_->DeRegisterPreEncodeCallback(channel_);
 
@@ -188,35 +274,23 @@ VideoSendStream::~VideoSendStream() {
   rtp_rtcp_->Release();
 }
 
-void VideoSendStream::PutFrame(const I420VideoFrame& frame) {
-  input_frame_.CopyFrame(frame);
-  SwapFrame(&input_frame_);
-}
-
 void VideoSendStream::SwapFrame(I420VideoFrame* frame) {
-  // TODO(pbos): Warn if frame is "too far" into the future, or too old. This
-  //             would help detect if frame's being used without NTP.
-  //             TO REVIEWER: Is there any good check for this? Should it be
-  //             skipped?
-  if (frame != &input_frame_)
-    input_frame_.SwapFrame(frame);
-
   // TODO(pbos): Local rendering should not be done on the capture thread.
   if (config_.local_renderer != NULL)
-    config_.local_renderer->RenderFrame(input_frame_, 0);
+    config_.local_renderer->RenderFrame(*frame, 0);
 
-  external_capture_->SwapFrame(&input_frame_);
+  external_capture_->SwapFrame(frame);
 }
 
 VideoSendStreamInput* VideoSendStream::Input() { return this; }
 
-void VideoSendStream::StartSending() {
+void VideoSendStream::Start() {
   transport_adapter_.Enable();
   video_engine_base_->StartSend(channel_);
   video_engine_base_->StartReceive(channel_);
 }
 
-void VideoSendStream::StopSending() {
+void VideoSendStream::Stop() {
   video_engine_base_->StopSend(channel_);
   video_engine_base_->StopReceive(channel_);
   transport_adapter_.Disable();
@@ -224,20 +298,19 @@ void VideoSendStream::StopSending() {
 
 bool VideoSendStream::ReconfigureVideoEncoder(
     const std::vector<VideoStream>& streams,
-    void* encoder_settings) {
+    const void* encoder_settings) {
   assert(!streams.empty());
   assert(config_.rtp.ssrcs.size() >= streams.size());
-  // TODO(pbos): Wire encoder_settings.
-  assert(encoder_settings == NULL);
-
-  // VideoStreams in config_.encoder_settings need to be locked.
-  CriticalSectionScoped crit(codec_lock_.get());
 
   VideoCodec video_codec;
   memset(&video_codec, 0, sizeof(video_codec));
-  video_codec.codecType =
-      (config_.encoder_settings.payload_name == "VP8" ? kVideoCodecVP8
-                                                      : kVideoCodecGeneric);
+  if (config_.encoder_settings.payload_name == "VP8") {
+    video_codec.codecType = kVideoCodecVP8;
+  } else if (config_.encoder_settings.payload_name == "H264") {
+    video_codec.codecType = kVideoCodecH264;
+  } else {
+    video_codec.codecType = kVideoCodecGeneric;
+  }
 
   if (video_codec.codecType == kVideoCodecVP8) {
     video_codec.codecSpecific.VP8.resilience = kResilientStream;
@@ -247,6 +320,20 @@ bool VideoSendStream::ReconfigureVideoEncoder(
     video_codec.codecSpecific.VP8.automaticResizeOn = false;
     video_codec.codecSpecific.VP8.frameDroppingOn = true;
     video_codec.codecSpecific.VP8.keyFrameInterval = 3000;
+  } else if (video_codec.codecType == kVideoCodecH264) {
+    video_codec.codecSpecific.H264.profile = kProfileBase;
+    video_codec.codecSpecific.H264.frameDroppingOn = true;
+    video_codec.codecSpecific.H264.keyFrameInterval = 3000;
+  }
+
+  if (video_codec.codecType == kVideoCodecVP8) {
+    if (encoder_settings != NULL) {
+      video_codec.codecSpecific.VP8 =
+          *reinterpret_cast<const VideoCodecVP8*>(encoder_settings);
+    }
+  } else {
+    // TODO(pbos): Support encoder_settings codec-agnostically.
+    assert(encoder_settings == NULL);
   }
 
   strncpy(video_codec.plName,
@@ -290,71 +377,87 @@ bool VideoSendStream::ReconfigureVideoEncoder(
     video_codec.qpMax = std::max(video_codec.qpMax,
                                  static_cast<unsigned int>(streams[i].max_qp));
   }
+  video_codec.startBitrate =
+      static_cast<unsigned int>(start_bitrate_bps_) / 1000;
 
   if (video_codec.minBitrate < kViEMinCodecBitrate)
     video_codec.minBitrate = kViEMinCodecBitrate;
   if (video_codec.maxBitrate < kViEMinCodecBitrate)
     video_codec.maxBitrate = kViEMinCodecBitrate;
-
-  video_codec.startBitrate = 300;
+  if (video_codec.startBitrate < video_codec.minBitrate)
+    video_codec.startBitrate = video_codec.minBitrate;
+  if (video_codec.startBitrate > video_codec.maxBitrate)
+    video_codec.startBitrate = video_codec.maxBitrate;
 
   if (video_codec.startBitrate < video_codec.minBitrate)
     video_codec.startBitrate = video_codec.minBitrate;
   if (video_codec.startBitrate > video_codec.maxBitrate)
     video_codec.startBitrate = video_codec.maxBitrate;
 
-  assert(config_.encoder_settings.streams[0].max_framerate > 0);
-  video_codec.maxFramerate = config_.encoder_settings.streams[0].max_framerate;
+  assert(streams[0].max_framerate > 0);
+  video_codec.maxFramerate = streams[0].max_framerate;
 
-  if (codec_->SetSendCodec(channel_, video_codec) != 0)
-    return false;
+  return codec_->SetSendCodec(channel_, video_codec) == 0;
+}
 
+bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
+  return network_->ReceivedRTCPPacket(
+             channel_, packet, static_cast<int>(length)) == 0;
+}
+
+VideoSendStream::Stats VideoSendStream::GetStats() const {
+  return stats_proxy_.GetStats();
+}
+
+void VideoSendStream::ConfigureSsrcs() {
   for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
-    rtp_rtcp_->SetLocalSSRC(channel_,
-                            config_.rtp.ssrcs[i],
-                            kViEStreamTypeNormal,
-                            static_cast<unsigned char>(i));
+    uint32_t ssrc = config_.rtp.ssrcs[i];
+    rtp_rtcp_->SetLocalSSRC(
+        channel_, ssrc, kViEStreamTypeNormal, static_cast<unsigned char>(i));
+    RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
+    if (it != suspended_ssrcs_.end())
+      rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
   }
 
-  config_.encoder_settings.streams = streams;
-  config_.encoder_settings.encoder_settings = encoder_settings;
-
-  if (config_.rtp.rtx.ssrcs.empty())
-    return true;
+  if (config_.rtp.rtx.ssrcs.empty()) {
+    assert(!config_.rtp.rtx.pad_with_redundant_payloads);
+    return;
+  }
 
   // Set up RTX.
   assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
-  for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
+  for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
+    uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
     rtp_rtcp_->SetLocalSSRC(channel_,
                             config_.rtp.rtx.ssrcs[i],
                             kViEStreamTypeRtx,
                             static_cast<unsigned char>(i));
+    RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
+    if (it != suspended_ssrcs_.end())
+      rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
   }
 
-  if (config_.rtp.rtx.payload_type != 0)
-    rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
-
-  return true;
-}
+  if (config_.rtp.rtx.pad_with_redundant_payloads) {
+    rtp_rtcp_->SetPadWithRedundantPayloads(channel_, true);
+  }
 
-bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
-  return network_->ReceivedRTCPPacket(
-             channel_, packet, static_cast<int>(length)) == 0;
+  assert(config_.rtp.rtx.payload_type >= 0);
+  rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
 }
 
-VideoSendStream::Stats VideoSendStream::GetStats() const {
-  return stats_proxy_->GetStats();
-}
+std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
+  std::map<uint32_t, RtpState> rtp_states;
+  for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
+    uint32_t ssrc = config_.rtp.ssrcs[i];
+    rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
+  }
 
-bool VideoSendStream::GetSendSideDelay(VideoSendStream::Stats* stats) {
-  return codec_->GetSendSideDelay(
-      channel_, &stats->avg_delay_ms, &stats->max_delay_ms);
-}
+  for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
+    uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
+    rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
+  }
 
-std::string VideoSendStream::GetCName() {
-  char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength];
-  rtp_rtcp_->GetRTCPCName(channel_, rtcp_cname);
-  return rtcp_cname;
+  return rtp_states;
 }
 
 }  // namespace internal