- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / video / video_send_stream.cc
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "webrtc/video/video_send_stream.h"
12
13 #include <string.h>
14
15 #include <string>
16 #include <vector>
17
18 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19 #include "webrtc/video_engine/include/vie_base.h"
20 #include "webrtc/video_engine/include/vie_capture.h"
21 #include "webrtc/video_engine/include/vie_codec.h"
22 #include "webrtc/video_engine/include/vie_external_codec.h"
23 #include "webrtc/video_engine/include/vie_image_process.h"
24 #include "webrtc/video_engine/include/vie_network.h"
25 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
26 #include "webrtc/video_send_stream.h"
27
28 namespace webrtc {
29 namespace internal {
30
31 // Super simple and temporary overuse logic. This will move to the application
32 // as soon as the new API allows changing send codec on the fly.
33 class ResolutionAdaptor : public webrtc::CpuOveruseObserver {
34  public:
35   ResolutionAdaptor(ViECodec* codec, int channel, size_t width, size_t height)
36       : codec_(codec),
37         channel_(channel),
38         max_width_(width),
39         max_height_(height) {}
40
41   virtual ~ResolutionAdaptor() {}
42
43   virtual void OveruseDetected() OVERRIDE {
44     VideoCodec codec;
45     if (codec_->GetSendCodec(channel_, codec) != 0)
46       return;
47
48     if (codec.width / 2 < min_width || codec.height / 2 < min_height)
49       return;
50
51     codec.width /= 2;
52     codec.height /= 2;
53     codec_->SetSendCodec(channel_, codec);
54   }
55
56   virtual void NormalUsage() OVERRIDE {
57     VideoCodec codec;
58     if (codec_->GetSendCodec(channel_, codec) != 0)
59       return;
60
61     if (codec.width * 2u > max_width_ || codec.height * 2u > max_height_)
62       return;
63
64     codec.width *= 2;
65     codec.height *= 2;
66     codec_->SetSendCodec(channel_, codec);
67   }
68
69  private:
70   // Temporary and arbitrary chosen minimum resolution.
71   static const size_t min_width = 160;
72   static const size_t min_height = 120;
73
74   ViECodec* codec_;
75   const int channel_;
76
77   const size_t max_width_;
78   const size_t max_height_;
79 };
80
81 VideoSendStream::VideoSendStream(newapi::Transport* transport,
82                                  bool overuse_detection,
83                                  webrtc::VideoEngine* video_engine,
84                                  const VideoSendStream::Config& config)
85     : transport_adapter_(transport), config_(config), external_codec_(NULL) {
86
87   if (config_.codec.numberOfSimulcastStreams > 0) {
88     assert(config_.rtp.ssrcs.size() == config_.codec.numberOfSimulcastStreams);
89   } else {
90     assert(config_.rtp.ssrcs.size() == 1);
91   }
92
93   video_engine_base_ = ViEBase::GetInterface(video_engine);
94   video_engine_base_->CreateChannel(channel_);
95   assert(channel_ != -1);
96
97   rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
98   assert(rtp_rtcp_ != NULL);
99
100   if (config_.rtp.ssrcs.size() == 1) {
101     rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.ssrcs[0]);
102   } else {
103     for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
104       rtp_rtcp_->SetLocalSSRC(channel_,
105                               config_.rtp.ssrcs[i],
106                               kViEStreamTypeNormal,
107                               static_cast<unsigned char>(i));
108     }
109   }
110   rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing);
111   if (!config_.rtp.rtx.ssrcs.empty()) {
112     assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
113     for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
114       rtp_rtcp_->SetLocalSSRC(channel_,
115                               config_.rtp.rtx.ssrcs[i],
116                               kViEStreamTypeRtx,
117                               static_cast<unsigned char>(i));
118     }
119
120     if (config_.rtp.rtx.rtx_payload_type != 0) {
121       rtp_rtcp_->SetRtxSendPayloadType(channel_,
122                                        config_.rtp.rtx.rtx_payload_type);
123     }
124   }
125
126   for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
127     const std::string& extension = config_.rtp.extensions[i].name;
128     int id = config_.rtp.extensions[i].id;
129     if (extension == "toffset") {
130       if (rtp_rtcp_->SetSendTimestampOffsetStatus(channel_, true, id) != 0)
131         abort();
132     } else if (extension == "abs-send-time") {
133       if (rtp_rtcp_->SetSendAbsoluteSendTimeStatus(channel_, true, id) != 0)
134         abort();
135     } else {
136       abort();  // Unsupported extension.
137     }
138   }
139
140   // Enable NACK, FEC or both.
141   if (config_.rtp.fec.red_payload_type != -1) {
142     assert(config_.rtp.fec.ulpfec_payload_type != -1);
143     if (config_.rtp.nack.rtp_history_ms > 0) {
144       rtp_rtcp_->SetHybridNACKFECStatus(
145           channel_,
146           true,
147           static_cast<unsigned char>(config_.rtp.fec.red_payload_type),
148           static_cast<unsigned char>(config_.rtp.fec.ulpfec_payload_type));
149     } else {
150       rtp_rtcp_->SetFECStatus(
151           channel_,
152           true,
153           static_cast<unsigned char>(config_.rtp.fec.red_payload_type),
154           static_cast<unsigned char>(config_.rtp.fec.ulpfec_payload_type));
155     }
156   } else {
157     rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
158   }
159
160   char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength];
161   assert(config_.rtp.c_name.length() < ViERTP_RTCP::KMaxRTCPCNameLength);
162   strncpy(rtcp_cname, config_.rtp.c_name.c_str(), sizeof(rtcp_cname) - 1);
163   rtcp_cname[sizeof(rtcp_cname) - 1] = '\0';
164
165   rtp_rtcp_->SetRTCPCName(channel_, rtcp_cname);
166
167   capture_ = ViECapture::GetInterface(video_engine);
168   capture_->AllocateExternalCaptureDevice(capture_id_, external_capture_);
169   capture_->ConnectCaptureDevice(capture_id_, channel_);
170
171   network_ = ViENetwork::GetInterface(video_engine);
172   assert(network_ != NULL);
173
174   network_->RegisterSendTransport(channel_, transport_adapter_);
175   // 28 to match packet overhead in ModuleRtpRtcpImpl.
176   network_->SetMTU(channel_,
177                    static_cast<unsigned int>(config_.rtp.max_packet_size + 28));
178
179   if (config.encoder) {
180     external_codec_ = ViEExternalCodec::GetInterface(video_engine);
181     if (external_codec_->RegisterExternalSendCodec(
182         channel_, config.codec.plType, config.encoder,
183         config.internal_source) != 0) {
184       abort();
185     }
186   }
187
188   codec_ = ViECodec::GetInterface(video_engine);
189   if (codec_->SetSendCodec(channel_, config_.codec) != 0) {
190     abort();
191   }
192
193   if (overuse_detection) {
194     overuse_observer_.reset(
195         new ResolutionAdaptor(codec_, channel_, config_.codec.width,
196                               config_.codec.height));
197     video_engine_base_->RegisterCpuOveruseObserver(channel_,
198                                                    overuse_observer_.get());
199   }
200
201   image_process_ = ViEImageProcess::GetInterface(video_engine);
202   image_process_->RegisterPreEncodeCallback(channel_,
203                                             config_.pre_encode_callback);
204
205   if (config.auto_mute) {
206     codec_->EnableAutoMuting(channel_);
207   }
208 }
209
210 VideoSendStream::~VideoSendStream() {
211   image_process_->DeRegisterPreEncodeCallback(channel_);
212
213   network_->DeregisterSendTransport(channel_);
214
215   capture_->DisconnectCaptureDevice(channel_);
216   capture_->ReleaseCaptureDevice(capture_id_);
217
218   if (external_codec_) {
219     external_codec_->DeRegisterExternalSendCodec(channel_,
220                                                  config_.codec.plType);
221   }
222
223   video_engine_base_->DeleteChannel(channel_);
224
225   image_process_->Release();
226   video_engine_base_->Release();
227   capture_->Release();
228   codec_->Release();
229   if (external_codec_)
230     external_codec_->Release();
231   network_->Release();
232   rtp_rtcp_->Release();
233 }
234
235 void VideoSendStream::PutFrame(const I420VideoFrame& frame,
236                                uint32_t time_since_capture_ms) {
237   // TODO(pbos): frame_copy should happen after the VideoProcessingModule has
238   //             resized the frame.
239   I420VideoFrame frame_copy;
240   frame_copy.CopyFrame(frame);
241
242   ViEVideoFrameI420 vf;
243
244   // TODO(pbos): This represents a memcpy step and is only required because
245   //             external_capture_ only takes ViEVideoFrameI420s.
246   vf.y_plane = frame_copy.buffer(kYPlane);
247   vf.u_plane = frame_copy.buffer(kUPlane);
248   vf.v_plane = frame_copy.buffer(kVPlane);
249   vf.y_pitch = frame.stride(kYPlane);
250   vf.u_pitch = frame.stride(kUPlane);
251   vf.v_pitch = frame.stride(kVPlane);
252   vf.width = frame.width();
253   vf.height = frame.height();
254
255   external_capture_->IncomingFrameI420(vf, frame.render_time_ms());
256
257   if (config_.local_renderer != NULL) {
258     config_.local_renderer->RenderFrame(frame, 0);
259   }
260 }
261
262 VideoSendStreamInput* VideoSendStream::Input() { return this; }
263
264 void VideoSendStream::StartSend() {
265   if (video_engine_base_->StartSend(channel_) != 0)
266     abort();
267   if (video_engine_base_->StartReceive(channel_) != 0)
268     abort();
269 }
270
271 void VideoSendStream::StopSend() {
272   if (video_engine_base_->StopSend(channel_) != 0)
273     abort();
274   if (video_engine_base_->StopReceive(channel_) != 0)
275     abort();
276 }
277
278 bool VideoSendStream::SetTargetBitrate(
279     int min_bitrate,
280     int max_bitrate,
281     const std::vector<SimulcastStream>& streams) {
282   return false;
283 }
284
285 void VideoSendStream::GetSendCodec(VideoCodec* send_codec) {
286   *send_codec = config_.codec;
287 }
288
289 bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
290   return network_->ReceivedRTCPPacket(
291              channel_, packet, static_cast<int>(length)) == 0;
292 }
293
294 }  // namespace internal
295 }  // namespace webrtc