blob: 928ae54004b073e433151fbd728dde9aa2978fe2 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +000011#include "video_engine/vie_encoder.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000012
13#include <cassert>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000015#include "common_video/libyuv/include/webrtc_libyuv.h"
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +000016#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
17#include "modules/utility/interface/process_thread.h"
18#include "modules/video_coding/codecs/interface/video_codec_interface.h"
19#include "modules/video_coding/main/interface/video_coding.h"
20#include "modules/video_coding/main/interface/video_coding_defines.h"
21#include "system_wrappers/interface/critical_section_wrapper.h"
22#include "system_wrappers/interface/tick_util.h"
23#include "system_wrappers/interface/trace.h"
24#include "video_engine/include/vie_codec.h"
25#include "video_engine/include/vie_image_process.h"
26#include "video_engine/vie_defines.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
niklase@google.com470e71d2011-07-07 08:21:25 +000028namespace webrtc {
29
stefan@webrtc.org439be292012-02-16 14:45:37 +000030class QMVideoSettingsCallback : public VCMQMSettingsCallback {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000031 public:
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +000032 explicit QMVideoSettingsCallback(VideoProcessingModule* vpm);
stefan@webrtc.org439be292012-02-16 14:45:37 +000033 ~QMVideoSettingsCallback();
niklase@google.com470e71d2011-07-07 08:21:25 +000034
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000035 // Update VPM with QM (quality modes: frame size & frame rate) settings.
36 WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frame_rate,
37 const WebRtc_UWord32 width,
38 const WebRtc_UWord32 height);
niklase@google.com470e71d2011-07-07 08:21:25 +000039
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000040 private:
41 VideoProcessingModule* vpm_;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000042};
niklase@google.com470e71d2011-07-07 08:21:25 +000043
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000044class ViEBitrateObserver : public BitrateObserver {
45 public:
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +000046 explicit ViEBitrateObserver(ViEEncoder* owner)
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000047 : owner_(owner) {
48 }
49 // Implements BitrateObserver.
50 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
51 const uint8_t fraction_lost,
52 const uint32_t rtt) {
53 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
54 }
55 private:
56 ViEEncoder* owner_;
57};
niklase@google.com470e71d2011-07-07 08:21:25 +000058
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000059ViEEncoder::ViEEncoder(WebRtc_Word32 engine_id,
60 WebRtc_Word32 channel_id,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000061 WebRtc_UWord32 number_of_cores,
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000062 ProcessThread& module_process_thread,
63 BitrateController* bitrate_controller)
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000064 : engine_id_(engine_id),
65 channel_id_(channel_id),
66 number_of_cores_(number_of_cores),
67 vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
68 channel_id))),
69 vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
70 channel_id))),
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000071 default_rtp_rtcp_(NULL),
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000072 callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
73 data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000074 bitrate_controller_(bitrate_controller),
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000075 paused_(false),
76 channels_dropping_delta_frames_(0),
77 drop_next_frame_(false),
78 fec_enabled_(false),
79 nack_enabled_(false),
80 codec_observer_(NULL),
81 effect_filter_(NULL),
82 module_process_thread_(module_process_thread),
83 has_received_sli_(false),
84 picture_id_sli_(0),
85 has_received_rpsi_(false),
86 picture_id_rpsi_(0),
stefan@webrtc.org97845122012-04-13 07:47:05 +000087 file_recorder_(channel_id),
88 qm_callback_(NULL) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000089 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
90 ViEId(engine_id, channel_id),
91 "%s(engine_id: %d) 0x%p - Constructor", __FUNCTION__, engine_id,
92 this);
pwestin@webrtc.orgce330352012-04-12 06:59:14 +000093
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000094 RtpRtcp::Configuration configuration;
95 configuration.id = ViEModuleId(engine_id_, channel_id_);
96 configuration.audio = false; // Video.
97
98 default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000099 bitrate_observer_.reset(new ViEBitrateObserver(this));
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000100}
101
102bool ViEEncoder::Init() {
103 if (vcm_.InitializeSender() != 0) {
104 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
105 ViEId(engine_id_, channel_id_),
106 "%s InitializeSender failure", __FUNCTION__);
107 return false;
108 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000109 vpm_.EnableTemporalDecimation(true);
110
111 // Enable/disable content analysis: off by default for now.
112 vpm_.EnableContentAnalysis(false);
113
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000114 if (module_process_thread_.RegisterModule(&vcm_) != 0) {
115 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
116 ViEId(engine_id_, channel_id_),
117 "%s RegisterModule failure", __FUNCTION__);
118 return false;
119 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000120 if (module_process_thread_.RegisterModule(default_rtp_rtcp_.get()) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000121 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
122 ViEId(engine_id_, channel_id_),
123 "%s RegisterModule failure", __FUNCTION__);
124 return false;
125 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000126
stefan@webrtc.org97845122012-04-13 07:47:05 +0000127 if (qm_callback_) {
128 delete qm_callback_;
129 }
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +0000130 qm_callback_ = new QMVideoSettingsCallback(&vpm_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000131
132#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000133 VideoCodec video_codec;
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000134 if (vcm_.Codec(webrtc::kVideoCodecVP8, &video_codec) != VCM_OK) {
135 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
136 ViEId(engine_id_, channel_id_),
137 "%s Codec failure", __FUNCTION__);
138 return false;
139 }
140 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000141 default_rtp_rtcp_->MaxDataPayloadLength()) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000142 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
143 ViEId(engine_id_, channel_id_),
144 "%s RegisterSendCodec failure", __FUNCTION__);
145 return false;
146 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000147 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000148 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
149 ViEId(engine_id_, channel_id_),
150 "%s RegisterSendPayload failure", __FUNCTION__);
151 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000152 }
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000153 if (default_rtp_rtcp_->RegisterSendRtpHeaderExtension(
154 kRtpExtensionTransmissionTimeOffset, 1) != 0) {
155 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
156 ViEId(engine_id_, channel_id_),
157 "%s RegisterSendRtpHeaderExtension failure", __FUNCTION__);
158 return false;
159 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000160#else
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000161 VideoCodec video_codec;
162 if (vcm_.Codec(webrtc::kVideoCodecI420, &video_codec) == VCM_OK) {
163 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000164 default_rtp_rtcp_->MaxDataPayloadLength());
165 default_rtp_rtcp_->RegisterSendPayload(video_codec);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000166 } else {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000167 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000168 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000169#endif
170
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000171 if (vcm_.RegisterTransportCallback(this) != 0) {
172 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
173 ViEId(engine_id_, channel_id_),
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000174 "ViEEncoder: VCM::RegisterTransportCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000175 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000176 }
177 if (vcm_.RegisterSendStatisticsCallback(this) != 0) {
178 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
179 ViEId(engine_id_, channel_id_),
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000180 "ViEEncoder: VCM::RegisterSendStatisticsCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000181 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000182 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000183 if (vcm_.RegisterVideoQMCallback(qm_callback_) != 0) {
184 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
185 ViEId(engine_id_, channel_id_),
186 "VCM::RegisterQMCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000187 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000188 }
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000189 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190}
191
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000192ViEEncoder::~ViEEncoder() {
193 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
194 ViEId(engine_id_, channel_id_),
195 "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000196 module_process_thread_.DeRegisterModule(&vcm_);
197 module_process_thread_.DeRegisterModule(&vpm_);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000198 module_process_thread_.DeRegisterModule(default_rtp_rtcp_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000199 delete &vcm_;
200 delete &vpm_;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000201 delete qm_callback_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000202}
203
mflodman@webrtc.org9ec883e2012-03-05 17:12:41 +0000204int ViEEncoder::Owner() const {
205 return channel_id_;
206}
207
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000208void ViEEncoder::Pause() {
209 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
210 ViEId(engine_id_, channel_id_),
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 "%s", __FUNCTION__);
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000212 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000213 paused_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214}
215
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000216void ViEEncoder::Restart() {
217 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
218 ViEId(engine_id_, channel_id_),
219 "%s", __FUNCTION__);
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000220 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000221 paused_ = false;
222}
223
224WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) {
225 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
226 ViEId(engine_id_, channel_id_),
227 "%s(%d)", __FUNCTION__, enable);
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000228 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000229
230 if (enable) {
231 channels_dropping_delta_frames_++;
232 } else {
233 channels_dropping_delta_frames_--;
234 if (channels_dropping_delta_frames_ < 0) {
235 channels_dropping_delta_frames_ = 0;
236 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
237 ViEId(engine_id_, channel_id_),
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000238 "%s: Called too many times", __FUNCTION__);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000239 return -1;
240 }
241 }
242 return 0;
243}
244
245WebRtc_UWord8 ViEEncoder::NumberOfCodecs() {
246 return vcm_.NumberOfCodecs();
247}
248
249WebRtc_Word32 ViEEncoder::GetCodec(WebRtc_UWord8 list_index,
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000250 VideoCodec* video_codec) {
251 if (vcm_.Codec(list_index, video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000252 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
253 ViEId(engine_id_, channel_id_), "%s: Could not get codec",
254 __FUNCTION__);
255 return -1;
256 }
257 return 0;
258}
259
260WebRtc_Word32 ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
261 WebRtc_UWord8 pl_type) {
262 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
263 ViEId(engine_id_, channel_id_), "%s: pltype %u", __FUNCTION__,
264 pl_type);
265
266 if (encoder == NULL)
267 return -1;
268
269 if (vcm_.RegisterExternalEncoder(encoder, pl_type) != VCM_OK) {
270 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
271 ViEId(engine_id_, channel_id_),
272 "Could not register external encoder");
273 return -1;
274 }
275 return 0;
276}
277
278WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 pl_type) {
279 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
280 ViEId(engine_id_, channel_id_),
281 "%s: pltype %u", __FUNCTION__, pl_type);
282
283 webrtc::VideoCodec current_send_codec;
284 if (vcm_.SendCodec(&current_send_codec) == VCM_OK) {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000285 if (vcm_.Bitrate(&current_send_codec.startBitrate) != 0) {
286 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
287 ViEId(engine_id_, channel_id_),
288 "Failed to get the current encoder target bitrate.");
289 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000290 }
291
292 if (vcm_.RegisterExternalEncoder(NULL, pl_type) != VCM_OK) {
293 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
294 ViEId(engine_id_, channel_id_),
295 "Could not deregister external encoder");
296 return -1;
297 }
298
299 // If the external encoder is the current send codeci, use vcm internal
300 // encoder.
301 if (current_send_codec.plType == pl_type) {
302 WebRtc_UWord16 max_data_payload_length =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000303 default_rtp_rtcp_->MaxDataPayloadLength();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000304 if (vcm_.RegisterSendCodec(&current_send_codec, number_of_cores_,
305 max_data_payload_length) != VCM_OK) {
306 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
307 ViEId(engine_id_, channel_id_),
308 "Could not use internal encoder");
309 return -1;
310 }
311 }
312 return 0;
313}
314
315WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
316 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
317 ViEId(engine_id_, channel_id_),
318 "%s: CodecType: %d, width: %u, height: %u", __FUNCTION__,
319 video_codec.codecType, video_codec.width, video_codec.height);
320
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000321 // Setting target width and height for VPM.
322 if (vpm_.SetTargetResolution(video_codec.width, video_codec.height,
323 video_codec.maxFramerate) != VPM_OK) {
324 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
325 ViEId(engine_id_, channel_id_),
326 "Could not set VPM target dimensions");
327 return -1;
328 }
329
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000330 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000331 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
332 ViEId(engine_id_, channel_id_),
333 "Could register RTP module video payload");
334 return -1;
335 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000336 // Convert from kbps to bps.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000337 default_rtp_rtcp_->SetTargetSendBitrate(video_codec.startBitrate * 1000);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000338
339 WebRtc_UWord16 max_data_payload_length =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000340 default_rtp_rtcp_->MaxDataPayloadLength();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000341
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000342 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
343 max_data_payload_length) != VCM_OK) {
344 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
345 ViEId(engine_id_, channel_id_),
346 "Could not register send codec");
347 return -1;
348 }
349
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000350 // Set this module as sending right away, let the slave module in the channel
351 // start and stop sending.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000352 if (default_rtp_rtcp_->Sending() == false) {
353 if (default_rtp_rtcp_->SetSendingStatus(true) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000354 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
355 ViEId(engine_id_, channel_id_),
356 "Could start RTP module sending");
357 return -1;
358 }
359 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000360 bitrate_controller_->SetBitrateObserver(bitrate_observer_.get(),
361 video_codec.startBitrate * 1000,
362 video_codec.minBitrate * 1000,
363 video_codec.maxBitrate * 1000);
364
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000365 return 0;
366}
367
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000368WebRtc_Word32 ViEEncoder::GetEncoder(VideoCodec* video_codec) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000369 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
370 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
371
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000372 if (vcm_.SendCodec(video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000373 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
374 ViEId(engine_id_, channel_id_),
375 "Could not get VCM send codec");
376 return -1;
377 }
378 return 0;
379}
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
381WebRtc_Word32 ViEEncoder::GetCodecConfigParameters(
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000382 unsigned char config_parameters[kConfigParameterSize],
383 unsigned char& config_parameters_size) {
384 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
385 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000387 WebRtc_Word32 num_parameters =
388 vcm_.CodecConfigParameters(config_parameters, kConfigParameterSize);
389 if (num_parameters <= 0) {
390 config_parameters_size = 0;
391 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
392 ViEId(engine_id_, channel_id_),
393 "Could not get config parameters");
394 return -1;
395 }
396 config_parameters_size = static_cast<unsigned char>(num_parameters);
397 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000398}
399
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000400WebRtc_Word32 ViEEncoder::ScaleInputImage(bool enable) {
401 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
402 ViEId(engine_id_, channel_id_), "%s(enable %d)", __FUNCTION__,
403 enable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000404
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000405 VideoFrameResampling resampling_mode = kFastRescaling;
406 if (enable == true) {
407 // kInterpolation is currently not supported.
408 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
409 ViEId(engine_id_, channel_id_), "%s not supported",
410 __FUNCTION__, enable);
411 return -1;
412 }
413 vpm_.SetInputFrameResampleMode(resampling_mode);
niklase@google.com470e71d2011-07-07 08:21:25 +0000414
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000415 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000416}
417
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000418RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
419 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
420 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000421
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000422 return default_rtp_rtcp_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +0000423}
424
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000425void ViEEncoder::DeliverFrame(int id,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000426 I420VideoFrame* video_frame,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000427 int num_csrcs,
428 const WebRtc_UWord32 CSRC[kRtpCsrcSize]) {
429 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
430 ViEId(engine_id_, channel_id_), "%s: %llu", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000431 video_frame->timestamp());
niklase@google.com470e71d2011-07-07 08:21:25 +0000432
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000433 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000434 CriticalSectionScoped cs(data_cs_.get());
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000435 if (paused_ || default_rtp_rtcp_->SendingMedia() == false) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000436 // We've paused or we have no channels attached, don't encode.
437 return;
438 }
439 if (drop_next_frame_) {
440 // Drop this frame.
441 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
442 ViEId(engine_id_, channel_id_),
443 "%s: Dropping frame %llu after a key fame", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000444 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000445 drop_next_frame_ = false;
446 return;
447 }
448 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000449
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000450 // Convert render time, in ms, to RTP timestamp.
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000451 const int kMsToRtpTimestamp = 90;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000452 const WebRtc_UWord32 time_stamp =
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000453 kMsToRtpTimestamp *
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000454 static_cast<WebRtc_UWord32>(video_frame->render_time_ms());
455 video_frame->set_timestamp(time_stamp);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000456 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000457 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000458 if (effect_filter_) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000459 unsigned int length = CalcBufferSize(kI420,
460 video_frame->width(),
461 video_frame->height());
462 scoped_array<uint8_t> video_buffer(new uint8_t[length]);
463 ExtractBuffer(*video_frame, length, video_buffer.get());
464 effect_filter_->Transform(length, video_buffer.get(),
465 video_frame->timestamp(), video_frame->width(),
466 video_frame->height());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000467 }
468 }
469 // Record raw frame.
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000470 file_recorder_.RecordVideoFrame(*video_frame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000472 // Make sure the CSRC list is correct.
473 if (num_csrcs > 0) {
474 WebRtc_UWord32 tempCSRC[kRtpCsrcSize];
475 for (int i = 0; i < num_csrcs; i++) {
476 if (CSRC[i] == 1) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000477 tempCSRC[i] = default_rtp_rtcp_->SSRC();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000478 } else {
479 tempCSRC[i] = CSRC[i];
480 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000482 default_rtp_rtcp_->SetCSRCs(tempCSRC, (WebRtc_UWord8) num_csrcs);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000483 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000484
485#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000486 if (vcm_.SendCodec() == webrtc::kVideoCodecVP8) {
487 webrtc::CodecSpecificInfo codec_specific_info;
488 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
489 if (has_received_sli_ || has_received_rpsi_) {
490 {
491 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI =
492 has_received_rpsi_;
493 codec_specific_info.codecSpecific.VP8.hasReceivedSLI =
494 has_received_sli_;
495 codec_specific_info.codecSpecific.VP8.pictureIdRPSI =
496 picture_id_rpsi_;
497 codec_specific_info.codecSpecific.VP8.pictureIdSLI =
498 picture_id_sli_;
499 }
500 has_received_sli_ = false;
501 has_received_rpsi_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000502 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000503 I420VideoFrame* decimated_frame = NULL;
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000504 const int ret = vpm_.PreprocessFrame(*video_frame, &decimated_frame);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000505 if (ret == 1) {
506 // Drop this frame.
507 return;
508 } else if (ret != VPM_OK) {
509 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
510 ViEId(engine_id_, channel_id_),
511 "%s: Error preprocessing frame %u", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000512 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000513 return;
514 }
515
516 VideoContentMetrics* content_metrics = NULL;
517 content_metrics = vpm_.ContentMetrics();
518
519 // Frame was not re-sampled => use original.
520 if (decimated_frame == NULL) {
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000521 decimated_frame = video_frame;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000522 }
523
524 if (vcm_.AddVideoFrame(*decimated_frame, content_metrics,
525 &codec_specific_info) != VCM_OK) {
526 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
527 ViEId(engine_id_, channel_id_),
528 "%s: Error encoding frame %u", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000529 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000530 }
531 return;
532 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000533#endif
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000534 // TODO(mflodman) Rewrite this to use code common to VP8 case.
535 // Pass frame via preprocessor.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000536 I420VideoFrame* decimated_frame = NULL;
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000537 const int ret = vpm_.PreprocessFrame(*video_frame, &decimated_frame);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000538 if (ret == 1) {
539 // Drop this frame.
540 return;
541 } else if (ret != VPM_OK) {
542 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
543 ViEId(engine_id_, channel_id_),
544 "%s: Error preprocessing frame %u", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000545 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000546 return;
547 }
548
549 // Frame was not sampled => use original.
550 if (decimated_frame == NULL) {
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000551 decimated_frame = video_frame;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000552 }
553 if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) {
554 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
555 ViEId(engine_id_, channel_id_), "%s: Error encoding frame %u",
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000556 __FUNCTION__, video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558}
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000560void ViEEncoder::DelayChanged(int id, int frame_delay) {
561 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
562 ViEId(engine_id_, channel_id_), "%s: %u", __FUNCTION__,
563 frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000564
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000565 default_rtp_rtcp_->SetCameraDelay(frame_delay);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000566 file_recorder_.SetFrameDelay(frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000567}
niklase@google.com470e71d2011-07-07 08:21:25 +0000568
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000569int ViEEncoder::GetPreferedFrameSettings(int* width,
570 int* height,
571 int* frame_rate) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000572 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
573 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000574
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000575 webrtc::VideoCodec video_codec;
576 memset(&video_codec, 0, sizeof(video_codec));
577 if (vcm_.SendCodec(&video_codec) != VCM_OK) {
578 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
579 ViEId(engine_id_, channel_id_),
580 "Could not get VCM send codec");
581 return -1;
582 }
583
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000584 *width = video_codec.width;
585 *height = video_codec.height;
586 *frame_rate = video_codec.maxFramerate;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000587 return 0;
588}
589
pwestin@webrtc.orgce330352012-04-12 06:59:14 +0000590int ViEEncoder::SendKeyFrame() {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000591 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
592 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
stefan@webrtc.orgc5300432012-10-08 07:06:53 +0000593 return vcm_.IntraFrameRequest(0);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000594}
595
596WebRtc_Word32 ViEEncoder::SendCodecStatistics(
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000597 WebRtc_UWord32* num_key_frames, WebRtc_UWord32* num_delta_frames) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000598 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
599 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
600
601 webrtc::VCMFrameCount sent_frames;
602 if (vcm_.SentFrameCount(sent_frames) != VCM_OK) {
603 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
604 ViEId(engine_id_, channel_id_),
605 "%s: Could not get sent frame information", __FUNCTION__);
606 return -1;
607 }
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000608 *num_key_frames = sent_frames.numKeyFrames;
609 *num_delta_frames = sent_frames.numDeltaFrames;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000610 return 0;
611}
612
stefan@webrtc.org439be292012-02-16 14:45:37 +0000613WebRtc_Word32 ViEEncoder::EstimatedSendBandwidth(
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000614 WebRtc_UWord32* available_bandwidth) const {
615 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
616 __FUNCTION__);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000617
618 if (!bitrate_controller_->AvailableBandwidth(available_bandwidth)) {
619 return -1;
620 }
621 return 0;
stefan@webrtc.org439be292012-02-16 14:45:37 +0000622}
623
624int ViEEncoder::CodecTargetBitrate(WebRtc_UWord32* bitrate) const {
625 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
626 __FUNCTION__);
627 if (vcm_.Bitrate(bitrate) != 0)
628 return -1;
629 return 0;
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000630}
631
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000632WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() {
633 bool fec_enabled = false;
634 WebRtc_UWord8 dummy_ptype_red = 0;
635 WebRtc_UWord8 dummy_ptypeFEC = 0;
636
637 // Updated protection method to VCM to get correct packetization sizes.
638 // FEC has larger overhead than NACK -> set FEC if used.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000639 WebRtc_Word32 error = default_rtp_rtcp_->GenericFECStatus(fec_enabled,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000640 dummy_ptype_red,
641 dummy_ptypeFEC);
642 if (error) {
643 return -1;
644 }
645
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000646 bool nack_enabled = (default_rtp_rtcp_->NACK() == kNackOff) ? false : true;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000647 if (fec_enabled_ == fec_enabled && nack_enabled_ == nack_enabled) {
648 // No change needed, we're already in correct state.
649 return 0;
650 }
651 fec_enabled_ = fec_enabled;
652 nack_enabled_ = nack_enabled;
653
654 // Set Video Protection for VCM.
655 if (fec_enabled && nack_enabled) {
656 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, true);
657 } else {
658 vcm_.SetVideoProtection(webrtc::kProtectionFEC, fec_enabled_);
659 vcm_.SetVideoProtection(webrtc::kProtectionNack, nack_enabled_);
660 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, false);
661 }
662
663 if (fec_enabled || nack_enabled) {
664 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
665 ViEId(engine_id_, channel_id_), "%s: FEC status ",
666 __FUNCTION__, fec_enabled);
667 vcm_.RegisterProtectionCallback(this);
668 // The send codec must be registered to set correct MTU.
669 webrtc::VideoCodec codec;
670 if (vcm_.SendCodec(&codec) == 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000671 WebRtc_UWord16 max_pay_load = default_rtp_rtcp_->MaxDataPayloadLength();
stefan@webrtc.org439be292012-02-16 14:45:37 +0000672 if (vcm_.Bitrate(&codec.startBitrate) != 0) {
673 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
674 ViEId(engine_id_, channel_id_),
675 "Failed to get the current encoder target bitrate.");
676 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000677 if (vcm_.RegisterSendCodec(&codec, number_of_cores_, max_pay_load) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000679 ViEId(engine_id_, channel_id_),
680 "%s: Failed to update Sendcodec when enabling FEC",
681 __FUNCTION__, fec_enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 return -1;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000683 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000684 }
685 return 0;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000686 } else {
687 // FEC and NACK are disabled.
688 vcm_.RegisterProtectionCallback(NULL);
689 }
690 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000691}
692
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000693WebRtc_Word32 ViEEncoder::SendData(
694 const FrameType frame_type,
695 const WebRtc_UWord8 payload_type,
696 const WebRtc_UWord32 time_stamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000697 int64_t capture_time_ms,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000698 const WebRtc_UWord8* payload_data,
699 const WebRtc_UWord32 payload_size,
700 const webrtc::RTPFragmentationHeader& fragmentation_header,
701 const RTPVideoHeader* rtp_video_hdr) {
702 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000703 CriticalSectionScoped cs(data_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000704 if (paused_) {
705 // Paused, don't send this packet.
706 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000708 if (channels_dropping_delta_frames_ &&
709 frame_type == webrtc::kVideoFrameKey) {
710 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
711 ViEId(engine_id_, channel_id_),
712 "%s: Sending key frame, drop next frame", __FUNCTION__);
713 drop_next_frame_ = true;
714 }
715 }
716
717 // New encoded data, hand over to the rtp module.
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000718 return default_rtp_rtcp_->SendOutgoingData(frame_type,
719 payload_type,
720 time_stamp,
721 capture_time_ms,
722 payload_data,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000723 payload_size,
724 &fragmentation_header,
725 rtp_video_hdr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726}
727
stefan@webrtc.orgf4c82862011-12-13 15:38:14 +0000728WebRtc_Word32 ViEEncoder::ProtectionRequest(
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000729 const FecProtectionParams* delta_fec_params,
730 const FecProtectionParams* key_fec_params,
stefan@webrtc.orgf4c82862011-12-13 15:38:14 +0000731 WebRtc_UWord32* sent_video_rate_bps,
732 WebRtc_UWord32* sent_nack_rate_bps,
733 WebRtc_UWord32* sent_fec_rate_bps) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000734 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
735 ViEId(engine_id_, channel_id_),
736 "%s, deltaFECRate: %u, key_fecrate: %u, "
marpan@webrtc.org71707aa2012-07-13 16:27:51 +0000737 "delta_use_uep_protection: %d, key_use_uep_protection: %d, "
738 "delta_max_fec_frames: %d, key_max_fec_frames: %d, "
739 "delta_mask_type: %d, key_mask_type: %d, ",
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000740 __FUNCTION__,
741 delta_fec_params->fec_rate,
742 key_fec_params->fec_rate,
743 delta_fec_params->use_uep_protection,
marpan@webrtc.org71707aa2012-07-13 16:27:51 +0000744 key_fec_params->use_uep_protection,
745 delta_fec_params->max_fec_frames,
746 key_fec_params->max_fec_frames,
747 delta_fec_params->fec_mask_type,
748 key_fec_params->fec_mask_type);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000749 if (default_rtp_rtcp_->SetFecParameters(delta_fec_params,
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000750 key_fec_params) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000751 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
752 ViEId(engine_id_, channel_id_),
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000753 "%s: Could not update FEC parameters", __FUNCTION__);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000754 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000755 default_rtp_rtcp_->BitrateSent(NULL,
stefan@webrtc.orgf4c82862011-12-13 15:38:14 +0000756 sent_video_rate_bps,
757 sent_fec_rate_bps,
758 sent_nack_rate_bps);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000759 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000760}
761
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000762WebRtc_Word32 ViEEncoder::SendStatistics(const WebRtc_UWord32 bit_rate,
763 const WebRtc_UWord32 frame_rate) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000764 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000765 if (codec_observer_) {
766 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
767 ViEId(engine_id_, channel_id_), "%s: bitrate %u, framerate %u",
768 __FUNCTION__, bit_rate, frame_rate);
769 codec_observer_->OutgoingRate(channel_id_, frame_rate, bit_rate);
770 }
771 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000772}
773
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000774WebRtc_Word32 ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000775 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000776 if (observer) {
777 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
778 ViEId(engine_id_, channel_id_), "%s: observer added",
779 __FUNCTION__);
780 if (codec_observer_) {
781 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
782 ViEId(engine_id_, channel_id_), "%s: observer already set.",
783 __FUNCTION__);
784 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000786 codec_observer_ = observer;
787 } else {
788 if (codec_observer_ == NULL) {
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000789 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
790 ViEId(engine_id_, channel_id_),
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000791 "%s: observer does not exist.", __FUNCTION__);
792 return -1;
793 }
794 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
795 ViEId(engine_id_, channel_id_), "%s: observer removed",
796 __FUNCTION__);
797 codec_observer_ = NULL;
798 }
799 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000800}
801
andrew@webrtc.org96636862012-09-20 23:33:17 +0000802void ViEEncoder::OnReceivedSLI(uint32_t /*ssrc*/,
803 uint8_t picture_id) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000804 picture_id_sli_ = picture_id;
805 has_received_sli_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000806}
807
andrew@webrtc.org96636862012-09-20 23:33:17 +0000808void ViEEncoder::OnReceivedRPSI(uint32_t /*ssrc*/,
809 uint64_t picture_id) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000810 picture_id_rpsi_ = picture_id;
811 has_received_rpsi_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000812}
813
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000814void ViEEncoder::OnReceivedIntraFrameRequest(uint32_t ssrc) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000815 // Key frame request from remote side, signal to VCM.
816 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
817 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000818
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000819 int idx = 0;
820 {
821 CriticalSectionScoped cs(data_cs_.get());
822 std::map<unsigned int, int>::iterator stream_it = ssrc_streams_.find(ssrc);
823 if (stream_it == ssrc_streams_.end()) {
824 assert(false);
825 return;
826 }
827 std::map<unsigned int, WebRtc_Word64>::iterator time_it =
828 time_last_intra_request_ms_.find(ssrc);
829 if (time_it == time_last_intra_request_ms_.end()) {
830 time_last_intra_request_ms_[ssrc] = 0;
831 }
832
833 WebRtc_Word64 now = TickTime::MillisecondTimestamp();
834 if (time_last_intra_request_ms_[ssrc] + kViEMinKeyRequestIntervalMs > now) {
835 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
836 ViEId(engine_id_, channel_id_),
837 "%s: Not encoding new intra due to timing", __FUNCTION__);
838 return;
839 }
840 time_last_intra_request_ms_[ssrc] = now;
841 idx = stream_it->second;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000842 }
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000843 // Release the critsect before triggering key frame.
844 vcm_.IntraFrameRequest(idx);
niklase@google.com470e71d2011-07-07 08:21:25 +0000845}
846
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000847void ViEEncoder::OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000848 CriticalSectionScoped cs(data_cs_.get());
849 std::map<unsigned int, int>::iterator it = ssrc_streams_.find(old_ssrc);
850 if (it == ssrc_streams_.end()) {
851 return;
852 }
853
854 ssrc_streams_[new_ssrc] = it->second;
855 ssrc_streams_.erase(it);
856
857 std::map<unsigned int, int64_t>::iterator time_it =
858 time_last_intra_request_ms_.find(old_ssrc);
859 int64_t last_intra_request_ms = 0;
860 if (time_it != time_last_intra_request_ms_.end()) {
861 last_intra_request_ms = time_it->second;
862 time_last_intra_request_ms_.erase(time_it);
863 }
864 time_last_intra_request_ms_[new_ssrc] = last_intra_request_ms;
865}
866
867bool ViEEncoder::SetSsrcs(const std::list<unsigned int>& ssrcs) {
868 VideoCodec codec;
869 if (vcm_.SendCodec(&codec) != 0)
870 return false;
871
872 if (codec.numberOfSimulcastStreams > 0 &&
873 ssrcs.size() != codec.numberOfSimulcastStreams) {
874 return false;
875 }
876
877 CriticalSectionScoped cs(data_cs_.get());
878 ssrc_streams_.clear();
879 time_last_intra_request_ms_.clear();
880 int idx = 0;
881 for (std::list<unsigned int>::const_iterator it = ssrcs.begin();
882 it != ssrcs.end(); ++it, ++idx) {
883 unsigned int ssrc = *it;
884 ssrc_streams_[ssrc] = idx;
885 }
886 return true;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000887}
888
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000889// Called from ViEBitrateObserver.
890void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps,
891 const uint8_t fraction_lost,
892 const uint32_t round_trip_time_ms) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000893 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
894 ViEId(engine_id_, channel_id_),
895 "%s(bitrate_bps: %u, fraction_lost: %u, rtt_ms: %u",
896 __FUNCTION__, bitrate_bps, fraction_lost, round_trip_time_ms);
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000897
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000898 vcm_.SetChannelParameters(bitrate_bps / 1000, fraction_lost,
899 round_trip_time_ms);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000900
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000901 default_rtp_rtcp_->SetTargetSendBitrate(bitrate_bps);
niklase@google.com470e71d2011-07-07 08:21:25 +0000902}
903
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000904WebRtc_Word32 ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000905 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000906 if (effect_filter == NULL) {
907 if (effect_filter_ == NULL) {
908 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
909 ViEId(engine_id_, channel_id_), "%s: no effect filter added",
910 __FUNCTION__);
911 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000913 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
914 ViEId(engine_id_, channel_id_), "%s: deregister effect filter",
915 __FUNCTION__);
916 } else {
917 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
918 ViEId(engine_id_, channel_id_), "%s: register effect",
919 __FUNCTION__);
920 if (effect_filter_) {
921 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
922 ViEId(engine_id_, channel_id_),
923 "%s: effect filter already added ", __FUNCTION__);
924 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000926 }
927 effect_filter_ = effect_filter;
928 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000929}
930
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000931ViEFileRecorder& ViEEncoder::GetOutgoingFileRecorder() {
932 return file_recorder_;
933}
niklase@google.com470e71d2011-07-07 08:21:25 +0000934
mikhal@webrtc.orge41bbdf2012-08-28 16:15:16 +0000935int ViEEncoder::StartDebugRecording(const char* fileNameUTF8) {
936 return vcm_.StartDebugRecording(fileNameUTF8);
937}
938
939int ViEEncoder::StopDebugRecording() {
940 return vcm_.StopDebugRecording();
941}
942
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +0000943QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessingModule* vpm)
944 : vpm_(vpm) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000945}
niklase@google.com470e71d2011-07-07 08:21:25 +0000946
stefan@webrtc.org439be292012-02-16 14:45:37 +0000947QMVideoSettingsCallback::~QMVideoSettingsCallback() {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000948}
949
stefan@webrtc.org439be292012-02-16 14:45:37 +0000950WebRtc_Word32 QMVideoSettingsCallback::SetVideoQMSettings(
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000951 const WebRtc_UWord32 frame_rate,
952 const WebRtc_UWord32 width,
953 const WebRtc_UWord32 height) {
marpan@webrtc.orgcf706c22012-03-27 21:04:13 +0000954 return vpm_->SetTargetResolution(width, height, frame_rate);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000955}
956
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000957} // namespace webrtc