blob: ea16f18b747d24a493b86aea6dab628d6b28f650 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 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
niklase@google.com470e71d2011-07-07 08:21:25 +000011#include "vie_encoder.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000012
13#include <cassert>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
15#include "critical_section_wrapper.h"
16#include "process_thread.h"
17#include "rtp_rtcp.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018#include "tick_util.h"
19#include "trace.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000020#include "video_codec_interface.h"
21#include "video_coding.h"
22#include "video_coding_defines.h"
23#include "vie_codec.h"
24#include "vie_defines.h"
25#include "vie_image_process.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
niklase@google.com470e71d2011-07-07 08:21:25 +000027namespace webrtc {
28
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000029class QMTestVideoSettingsCallback : public VCMQMSettingsCallback {
30 public:
31 QMTestVideoSettingsCallback(VideoProcessingModule* vpm,
32 VideoCodingModule* vcm,
33 WebRtc_Word32 num_of_cores_,
34 WebRtc_Word32 max_payload_length_);
35 ~QMTestVideoSettingsCallback();
niklase@google.com470e71d2011-07-07 08:21:25 +000036
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000037 // Update VPM with QM (quality modes: frame size & frame rate) settings.
38 WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frame_rate,
39 const WebRtc_UWord32 width,
40 const WebRtc_UWord32 height);
niklase@google.com470e71d2011-07-07 08:21:25 +000041
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000042 WebRtc_Word32 SetMaxPayloadLength(WebRtc_Word32 num_cores);
niklase@google.com470e71d2011-07-07 08:21:25 +000043
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000044 private:
45 VideoProcessingModule* vpm_;
46 VideoCodingModule* vcm_;
47 WebRtc_Word32 num_cores_;
48 WebRtc_Word32 max_payload_length_;
49};
niklase@google.com470e71d2011-07-07 08:21:25 +000050
niklase@google.com470e71d2011-07-07 08:21:25 +000051
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000052ViEEncoder::ViEEncoder(WebRtc_Word32 engine_id, WebRtc_Word32 channel_id,
53 WebRtc_UWord32 number_of_cores,
54 ProcessThread& module_process_thread)
55 : engine_id_(engine_id),
56 channel_id_(channel_id),
57 number_of_cores_(number_of_cores),
58 vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
59 channel_id))),
60 vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
61 channel_id))),
62 default_rtp_rtcp_(*RtpRtcp::CreateRtpRtcp(
63 ViEModuleId(engine_id, channel_id), false)),
64 callback_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
65 data_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
66 paused_(false),
67 channels_dropping_delta_frames_(0),
68 drop_next_frame_(false),
69 fec_enabled_(false),
70 nack_enabled_(false),
71 codec_observer_(NULL),
72 effect_filter_(NULL),
73 module_process_thread_(module_process_thread),
74 has_received_sli_(false),
75 picture_id_sli_(0),
76 has_received_rpsi_(false),
77 picture_id_rpsi_(0),
78 file_recorder_(channel_id) {
79 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
80 ViEId(engine_id, channel_id),
81 "%s(engine_id: %d) 0x%p - Constructor", __FUNCTION__, engine_id,
82 this);
83 for (int i = 0; i < kMaxSimulcastStreams; i++) {
84 time_last_intra_request_ms_[i] = 0;
85 }
86 vcm_.InitializeSender();
87 vpm_.EnableTemporalDecimation(true);
88
89 // Enable/disable content analysis: off by default for now.
90 vpm_.EnableContentAnalysis(false);
91
92 module_process_thread_.RegisterModule(&vcm_);
93 default_rtp_rtcp_.InitSender();
94 default_rtp_rtcp_.RegisterIncomingVideoCallback(this);
95 default_rtp_rtcp_.RegisterIncomingRTCPCallback(this);
96 module_process_thread_.RegisterModule(&default_rtp_rtcp_);
97
98 qm_callback_ = new QMTestVideoSettingsCallback(
99 &vpm_, &vcm_, number_of_cores, default_rtp_rtcp_.MaxDataPayloadLength());
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
101#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000102 VideoCodec video_codec;
103 if (vcm_.Codec(webrtc::kVideoCodecVP8, &video_codec) == VCM_OK) {
104 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
105 default_rtp_rtcp_.MaxDataPayloadLength());
106 default_rtp_rtcp_.RegisterSendPayload(video_codec);
107 } else {
108 assert(false);
109 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000110#else
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000111 VideoCodec video_codec;
112 if (vcm_.Codec(webrtc::kVideoCodecI420, &video_codec) == VCM_OK) {
113 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
114 default_rtp_rtcp_.MaxDataPayloadLength());
115 default_rtp_rtcp_.RegisterSendPayload(video_codec);
116 } else {
117 assert(false);
118 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000119#endif
120
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000121 if (vcm_.RegisterTransportCallback(this) != 0) {
122 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
123 ViEId(engine_id_, channel_id_),
124 "%s: VCM::RegisterTransportCallback failure");
125 }
126 if (vcm_.RegisterSendStatisticsCallback(this) != 0) {
127 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
128 ViEId(engine_id_, channel_id_),
129 "%s: VCM::RegisterSendStatisticsCallback failure");
130 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000131
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000132 if (vcm_.RegisterVideoQMCallback(qm_callback_) != 0) {
133 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
134 ViEId(engine_id_, channel_id_),
135 "VCM::RegisterQMCallback failure");
136 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000137}
138
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000139ViEEncoder::~ViEEncoder() {
140 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
141 ViEId(engine_id_, channel_id_),
142 "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000144 if (default_rtp_rtcp_.NumberChildModules() > 0) {
145 assert(false);
146 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
147 ViEId(engine_id_, channel_id_),
148 "Channels still attached %d, leaking memory",
149 default_rtp_rtcp_.NumberChildModules());
150 return;
151 }
152 module_process_thread_.DeRegisterModule(&vcm_);
153 module_process_thread_.DeRegisterModule(&vpm_);
154 module_process_thread_.DeRegisterModule(&default_rtp_rtcp_);
155 delete &vcm_;
156 delete &vpm_;
157 delete &default_rtp_rtcp_;
158 delete &callback_critsect_;
159 delete &data_critsect_;
160 delete qm_callback_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000161}
162
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000163void ViEEncoder::Pause() {
164 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
165 ViEId(engine_id_, channel_id_),
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 "%s", __FUNCTION__);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000167 CriticalSectionScoped cs(data_critsect_);
168 paused_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000169}
170
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000171void ViEEncoder::Restart() {
172 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
173 ViEId(engine_id_, channel_id_),
174 "%s", __FUNCTION__);
175 CriticalSectionScoped cs(data_critsect_);
176 paused_ = false;
177}
178
179WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) {
180 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
181 ViEId(engine_id_, channel_id_),
182 "%s(%d)", __FUNCTION__, enable);
183 CriticalSectionScoped cs(data_critsect_);
184
185 if (enable) {
186 channels_dropping_delta_frames_++;
187 } else {
188 channels_dropping_delta_frames_--;
189 if (channels_dropping_delta_frames_ < 0) {
190 channels_dropping_delta_frames_ = 0;
191 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
192 ViEId(engine_id_, channel_id_),
193 "%s: Called too many times", __FUNCTION__, enable);
194 return -1;
195 }
196 }
197 return 0;
198}
199
200WebRtc_UWord8 ViEEncoder::NumberOfCodecs() {
201 return vcm_.NumberOfCodecs();
202}
203
204WebRtc_Word32 ViEEncoder::GetCodec(WebRtc_UWord8 list_index,
205 webrtc::VideoCodec& video_codec) {
206 if (vcm_.Codec(list_index, &video_codec) != 0) {
207 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
208 ViEId(engine_id_, channel_id_), "%s: Could not get codec",
209 __FUNCTION__);
210 return -1;
211 }
212 return 0;
213}
214
215WebRtc_Word32 ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
216 WebRtc_UWord8 pl_type) {
217 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
218 ViEId(engine_id_, channel_id_), "%s: pltype %u", __FUNCTION__,
219 pl_type);
220
221 if (encoder == NULL)
222 return -1;
223
224 if (vcm_.RegisterExternalEncoder(encoder, pl_type) != VCM_OK) {
225 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
226 ViEId(engine_id_, channel_id_),
227 "Could not register external encoder");
228 return -1;
229 }
230 return 0;
231}
232
233WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 pl_type) {
234 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
235 ViEId(engine_id_, channel_id_),
236 "%s: pltype %u", __FUNCTION__, pl_type);
237
238 webrtc::VideoCodec current_send_codec;
239 if (vcm_.SendCodec(&current_send_codec) == VCM_OK) {
240 current_send_codec.startBitrate = vcm_.Bitrate();
241 }
242
243 if (vcm_.RegisterExternalEncoder(NULL, pl_type) != VCM_OK) {
244 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
245 ViEId(engine_id_, channel_id_),
246 "Could not deregister external encoder");
247 return -1;
248 }
249
250 // If the external encoder is the current send codeci, use vcm internal
251 // encoder.
252 if (current_send_codec.plType == pl_type) {
253 WebRtc_UWord16 max_data_payload_length =
254 default_rtp_rtcp_.MaxDataPayloadLength();
255 if (vcm_.RegisterSendCodec(&current_send_codec, number_of_cores_,
256 max_data_payload_length) != VCM_OK) {
257 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
258 ViEId(engine_id_, channel_id_),
259 "Could not use internal encoder");
260 return -1;
261 }
262 }
263 return 0;
264}
265
266WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
267 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
268 ViEId(engine_id_, channel_id_),
269 "%s: CodecType: %d, width: %u, height: %u", __FUNCTION__,
270 video_codec.codecType, video_codec.width, video_codec.height);
271
272 // Convert from kbps to bps.
273 if (default_rtp_rtcp_.SetSendBitrate(video_codec.startBitrate * 1000,
274 video_codec.minBitrate,
275 video_codec.maxBitrate) != 0) {
276 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
277 ViEId(engine_id_, channel_id_),
278 "Could not set RTP module bitrates");
279 return -1;
280 }
281
282 // Setting target width and height for VPM.
283 if (vpm_.SetTargetResolution(video_codec.width, video_codec.height,
284 video_codec.maxFramerate) != VPM_OK) {
285 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
286 ViEId(engine_id_, channel_id_),
287 "Could not set VPM target dimensions");
288 return -1;
289 }
290
291 if (default_rtp_rtcp_.RegisterSendPayload(video_codec) != 0) {
292 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
293 ViEId(engine_id_, channel_id_),
294 "Could register RTP module video payload");
295 return -1;
296 }
297
298 WebRtc_UWord16 max_data_payload_length =
299 default_rtp_rtcp_.MaxDataPayloadLength();
300
301 qm_callback_->SetMaxPayloadLength(max_data_payload_length);
302
303 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
304 max_data_payload_length) != VCM_OK) {
305 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
306 ViEId(engine_id_, channel_id_),
307 "Could not register send codec");
308 return -1;
309 }
310
311 data_critsect_.Enter();
312 memcpy(&send_codec_, &video_codec, sizeof(send_codec_));
313 data_critsect_.Leave();
314
315 // Set this module as sending right away, let the slave module in the channel
316 // start and stop sending.
317 if (default_rtp_rtcp_.Sending() == false) {
318 if (default_rtp_rtcp_.SetSendingStatus(true) != 0) {
319 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
320 ViEId(engine_id_, channel_id_),
321 "Could start RTP module sending");
322 return -1;
323 }
324 }
325 return 0;
326}
327
328WebRtc_Word32 ViEEncoder::GetEncoder(webrtc::VideoCodec& video_codec) {
329 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
330 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
331
332 if (vcm_.SendCodec(&video_codec) != 0) {
333 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
334 ViEId(engine_id_, channel_id_),
335 "Could not get VCM send codec");
336 return -1;
337 }
338 return 0;
339}
niklase@google.com470e71d2011-07-07 08:21:25 +0000340
341WebRtc_Word32 ViEEncoder::GetCodecConfigParameters(
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000342 unsigned char config_parameters[kConfigParameterSize],
343 unsigned char& config_parameters_size) {
344 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
345 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000346
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000347 WebRtc_Word32 num_parameters =
348 vcm_.CodecConfigParameters(config_parameters, kConfigParameterSize);
349 if (num_parameters <= 0) {
350 config_parameters_size = 0;
351 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
352 ViEId(engine_id_, channel_id_),
353 "Could not get config parameters");
354 return -1;
355 }
356 config_parameters_size = static_cast<unsigned char>(num_parameters);
357 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000358}
359
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000360WebRtc_Word32 ViEEncoder::ScaleInputImage(bool enable) {
361 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
362 ViEId(engine_id_, channel_id_), "%s(enable %d)", __FUNCTION__,
363 enable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000364
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000365 VideoFrameResampling resampling_mode = kFastRescaling;
366 if (enable == true) {
367 // kInterpolation is currently not supported.
368 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
369 ViEId(engine_id_, channel_id_), "%s not supported",
370 __FUNCTION__, enable);
371 return -1;
372 }
373 vpm_.SetInputFrameResampleMode(resampling_mode);
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000375 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000376}
377
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000378RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
379 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
380 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000381
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000382 return &default_rtp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000383}
384
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000385void ViEEncoder::DeliverFrame(int id, webrtc::VideoFrame& video_frame,
386 int num_csrcs,
387 const WebRtc_UWord32 CSRC[kRtpCsrcSize]) {
388 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
389 ViEId(engine_id_, channel_id_), "%s: %llu", __FUNCTION__,
390 video_frame.TimeStamp());
niklase@google.com470e71d2011-07-07 08:21:25 +0000391
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000392 {
393 CriticalSectionScoped cs(data_critsect_);
394 if (paused_ || default_rtp_rtcp_.SendingMedia() == false) {
395 // We've paused or we have no channels attached, don't encode.
396 return;
397 }
398 if (drop_next_frame_) {
399 // Drop this frame.
400 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
401 ViEId(engine_id_, channel_id_),
402 "%s: Dropping frame %llu after a key fame", __FUNCTION__,
403 video_frame.TimeStamp());
404 drop_next_frame_ = false;
405 return;
406 }
407 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000408
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000409 // Convert render time, in ms, to RTP timestamp.
410 const WebRtc_UWord32 time_stamp =
411 90 * static_cast<WebRtc_UWord32>(video_frame.RenderTimeMs());
412 video_frame.SetTimeStamp(time_stamp);
413 {
414 CriticalSectionScoped cs(callback_critsect_);
415 if (effect_filter_) {
416 effect_filter_->Transform(video_frame.Length(), video_frame.Buffer(),
417 video_frame.TimeStamp(),
418 video_frame.Width(), video_frame.Height());
419 }
420 }
421 // Record raw frame.
422 file_recorder_.RecordVideoFrame(video_frame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000423
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000424 // Make sure the CSRC list is correct.
425 if (num_csrcs > 0) {
426 WebRtc_UWord32 tempCSRC[kRtpCsrcSize];
427 for (int i = 0; i < num_csrcs; i++) {
428 if (CSRC[i] == 1) {
429 tempCSRC[i] = default_rtp_rtcp_.SSRC();
430 } else {
431 tempCSRC[i] = CSRC[i];
432 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000434 default_rtp_rtcp_.SetCSRCs(tempCSRC, (WebRtc_UWord8) num_csrcs);
435 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000436
437#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000438 if (vcm_.SendCodec() == webrtc::kVideoCodecVP8) {
439 webrtc::CodecSpecificInfo codec_specific_info;
440 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
441 if (has_received_sli_ || has_received_rpsi_) {
442 {
443 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI =
444 has_received_rpsi_;
445 codec_specific_info.codecSpecific.VP8.hasReceivedSLI =
446 has_received_sli_;
447 codec_specific_info.codecSpecific.VP8.pictureIdRPSI =
448 picture_id_rpsi_;
449 codec_specific_info.codecSpecific.VP8.pictureIdSLI =
450 picture_id_sli_;
451 }
452 has_received_sli_ = false;
453 has_received_rpsi_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000454 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000455 VideoFrame* decimated_frame = NULL;
456 const int ret = vpm_.PreprocessFrame(&video_frame, &decimated_frame);
457 if (ret == 1) {
458 // Drop this frame.
459 return;
460 } else if (ret != VPM_OK) {
461 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
462 ViEId(engine_id_, channel_id_),
463 "%s: Error preprocessing frame %u", __FUNCTION__,
464 video_frame.TimeStamp());
465 return;
466 }
467
468 VideoContentMetrics* content_metrics = NULL;
469 content_metrics = vpm_.ContentMetrics();
470
471 // Frame was not re-sampled => use original.
472 if (decimated_frame == NULL) {
473 decimated_frame = &video_frame;
474 }
475
476 if (vcm_.AddVideoFrame(*decimated_frame, content_metrics,
477 &codec_specific_info) != VCM_OK) {
478 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
479 ViEId(engine_id_, channel_id_),
480 "%s: Error encoding frame %u", __FUNCTION__,
481 video_frame.TimeStamp());
482 }
483 return;
484 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000485#endif
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000486 // TODO(mflodman) Rewrite this to use code common to VP8 case.
487 // Pass frame via preprocessor.
488 VideoFrame* decimated_frame = NULL;
489 const int ret = vpm_.PreprocessFrame(&video_frame, &decimated_frame);
490 if (ret == 1) {
491 // Drop this frame.
492 return;
493 } else if (ret != VPM_OK) {
494 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
495 ViEId(engine_id_, channel_id_),
496 "%s: Error preprocessing frame %u", __FUNCTION__,
497 video_frame.TimeStamp());
498 return;
499 }
500
501 // Frame was not sampled => use original.
502 if (decimated_frame == NULL) {
503 decimated_frame = &video_frame;
504 }
505 if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) {
506 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
507 ViEId(engine_id_, channel_id_), "%s: Error encoding frame %u",
508 __FUNCTION__, video_frame.TimeStamp());
509 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000510}
niklase@google.com470e71d2011-07-07 08:21:25 +0000511
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000512void ViEEncoder::DelayChanged(int id, int frame_delay) {
513 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
514 ViEId(engine_id_, channel_id_), "%s: %u", __FUNCTION__,
515 frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000516
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000517 default_rtp_rtcp_.SetCameraDelay(frame_delay);
518 file_recorder_.SetFrameDelay(frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000519}
niklase@google.com470e71d2011-07-07 08:21:25 +0000520
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000521int ViEEncoder::GetPreferedFrameSettings(int& width,
522 int& height,
523 int& frame_rate) {
524 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
525 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000526
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000527 webrtc::VideoCodec video_codec;
528 memset(&video_codec, 0, sizeof(video_codec));
529 if (vcm_.SendCodec(&video_codec) != VCM_OK) {
530 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
531 ViEId(engine_id_, channel_id_),
532 "Could not get VCM send codec");
533 return -1;
534 }
535
536 width = video_codec.width;
537 height = video_codec.height;
538 frame_rate = video_codec.maxFramerate;
539 return 0;
540}
541
542WebRtc_Word32 ViEEncoder::SendKeyFrame() {
543 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
544 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
545 return vcm_.FrameTypeRequest(kVideoFrameKey, 0); // Simulcast idx = 0.
546}
547
548WebRtc_Word32 ViEEncoder::SendCodecStatistics(
549 WebRtc_UWord32& num_key_frames, WebRtc_UWord32& num_delta_frames) {
550 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
551 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
552
553 webrtc::VCMFrameCount sent_frames;
554 if (vcm_.SentFrameCount(sent_frames) != VCM_OK) {
555 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
556 ViEId(engine_id_, channel_id_),
557 "%s: Could not get sent frame information", __FUNCTION__);
558 return -1;
559 }
560 num_key_frames = sent_frames.numKeyFrames;
561 num_delta_frames = sent_frames.numDeltaFrames;
562 return 0;
563}
564
565WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() {
566 bool fec_enabled = false;
567 WebRtc_UWord8 dummy_ptype_red = 0;
568 WebRtc_UWord8 dummy_ptypeFEC = 0;
569
570 // Updated protection method to VCM to get correct packetization sizes.
571 // FEC has larger overhead than NACK -> set FEC if used.
572 WebRtc_Word32 error = default_rtp_rtcp_.GenericFECStatus(fec_enabled,
573 dummy_ptype_red,
574 dummy_ptypeFEC);
575 if (error) {
576 return -1;
577 }
578
579 bool nack_enabled = (default_rtp_rtcp_.NACK() == kNackOff) ? false : true;
580 if (fec_enabled_ == fec_enabled && nack_enabled_ == nack_enabled) {
581 // No change needed, we're already in correct state.
582 return 0;
583 }
584 fec_enabled_ = fec_enabled;
585 nack_enabled_ = nack_enabled;
586
587 // Set Video Protection for VCM.
588 if (fec_enabled && nack_enabled) {
589 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, true);
590 } else {
591 vcm_.SetVideoProtection(webrtc::kProtectionFEC, fec_enabled_);
592 vcm_.SetVideoProtection(webrtc::kProtectionNack, nack_enabled_);
593 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, false);
594 }
595
596 if (fec_enabled || nack_enabled) {
597 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
598 ViEId(engine_id_, channel_id_), "%s: FEC status ",
599 __FUNCTION__, fec_enabled);
600 vcm_.RegisterProtectionCallback(this);
601 // The send codec must be registered to set correct MTU.
602 webrtc::VideoCodec codec;
603 if (vcm_.SendCodec(&codec) == 0) {
604 WebRtc_UWord16 max_pay_load = default_rtp_rtcp_.MaxDataPayloadLength();
605 codec.startBitrate = vcm_.Bitrate();
606 if (vcm_.RegisterSendCodec(&codec, number_of_cores_, max_pay_load) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000607 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000608 ViEId(engine_id_, channel_id_),
609 "%s: Failed to update Sendcodec when enabling FEC",
610 __FUNCTION__, fec_enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +0000611 return -1;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000612 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 }
614 return 0;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000615 } else {
616 // FEC and NACK are disabled.
617 vcm_.RegisterProtectionCallback(NULL);
618 }
619 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620}
621
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000622WebRtc_Word32 ViEEncoder::SendData(
623 const FrameType frame_type,
624 const WebRtc_UWord8 payload_type,
625 const WebRtc_UWord32 time_stamp,
626 const WebRtc_UWord8* payload_data,
627 const WebRtc_UWord32 payload_size,
628 const webrtc::RTPFragmentationHeader& fragmentation_header,
629 const RTPVideoHeader* rtp_video_hdr) {
630 {
631 CriticalSectionScoped cs(data_critsect_);
632 if (paused_) {
633 // Paused, don't send this packet.
634 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000636 if (channels_dropping_delta_frames_ &&
637 frame_type == webrtc::kVideoFrameKey) {
638 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
639 ViEId(engine_id_, channel_id_),
640 "%s: Sending key frame, drop next frame", __FUNCTION__);
641 drop_next_frame_ = true;
642 }
643 }
644
645 // New encoded data, hand over to the rtp module.
646 return default_rtp_rtcp_.SendOutgoingData(frame_type, payload_type,
647 time_stamp, payload_data,
648 payload_size, &fragmentation_header,
649 rtp_video_hdr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000650}
651
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000652WebRtc_Word32 ViEEncoder::ProtectionRequest(const WebRtc_UWord8 delta_fecrate,
653 const WebRtc_UWord8 key_fecrate,
654 const bool delta_use_uep_protection,
655 const bool key_use_uep_protection,
656 const bool nack) {
657 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
658 ViEId(engine_id_, channel_id_),
659 "%s, deltaFECRate: %u, key_fecrate: %u, "
660 "delta_use_uep_protection: %d, key_use_uep_protection: %d, "
661 "nack: %d", __FUNCTION__, delta_fecrate, key_fecrate,
662 delta_use_uep_protection, key_use_uep_protection, nack);
niklase@google.com470e71d2011-07-07 08:21:25 +0000663
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000664 if (default_rtp_rtcp_.SetFECCodeRate(key_fecrate, delta_fecrate) != 0) {
665 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
666 ViEId(engine_id_, channel_id_),
667 "%s: Could not update FEC code rate", __FUNCTION__);
668 }
669 if (default_rtp_rtcp_.SetFECUepProtection(key_use_uep_protection,
670 delta_use_uep_protection) != 0) {
671 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
672 ViEId(engine_id_, channel_id_),
673 "%s: Could not update FEC-UEP protection", __FUNCTION__);
674 }
675 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000676}
677
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000678WebRtc_Word32 ViEEncoder::SendStatistics(const WebRtc_UWord32 bit_rate,
679 const WebRtc_UWord32 frame_rate) {
680 CriticalSectionScoped cs(callback_critsect_);
681 if (codec_observer_) {
682 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
683 ViEId(engine_id_, channel_id_), "%s: bitrate %u, framerate %u",
684 __FUNCTION__, bit_rate, frame_rate);
685 codec_observer_->OutgoingRate(channel_id_, frame_rate, bit_rate);
686 }
687 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000688}
689
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000690WebRtc_Word32 ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) {
691 CriticalSectionScoped cs(callback_critsect_);
692 if (observer) {
693 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
694 ViEId(engine_id_, channel_id_), "%s: observer added",
695 __FUNCTION__);
696 if (codec_observer_) {
697 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
698 ViEId(engine_id_, channel_id_), "%s: observer already set.",
699 __FUNCTION__);
700 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000702 codec_observer_ = observer;
703 } else {
704 if (codec_observer_ == NULL) {
705 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engine_id_,
706 channel_id_),
707 "%s: observer does not exist.", __FUNCTION__);
708 return -1;
709 }
710 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
711 ViEId(engine_id_, channel_id_), "%s: observer removed",
712 __FUNCTION__);
713 codec_observer_ = NULL;
714 }
715 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000716}
717
niklase@google.com470e71d2011-07-07 08:21:25 +0000718void ViEEncoder::OnSLIReceived(const WebRtc_Word32 id,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000719 const WebRtc_UWord8 picture_id) {
720 picture_id_sli_ = picture_id;
721 has_received_sli_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000722}
723
724void ViEEncoder::OnRPSIReceived(const WebRtc_Word32 id,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000725 const WebRtc_UWord64 picture_id) {
726 picture_id_rpsi_ = picture_id;
727 has_received_rpsi_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000728}
729
niklase@google.com470e71d2011-07-07 08:21:25 +0000730void ViEEncoder::OnReceivedIntraFrameRequest(const WebRtc_Word32 id,
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000731 const FrameType type,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000732 const WebRtc_UWord8 stream_idx) {
733 assert(stream_idx < kMaxSimulcastStreams);
niklase@google.com470e71d2011-07-07 08:21:25 +0000734
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000735 // Key frame request from remote side, signal to VCM.
736 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
737 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000738
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000739 WebRtc_Word64 now = TickTime::MillisecondTimestamp();
740 if (time_last_intra_request_ms_[stream_idx] + kViEMinKeyRequestIntervalMs >
741 now) {
742 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
743 ViEId(engine_id_, channel_id_),
744 "%s: Not not encoding new intra due to timing", __FUNCTION__);
745 return;
746 }
747 vcm_.FrameTypeRequest(type, stream_idx);
748 time_last_intra_request_ms_[stream_idx] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000749}
750
niklase@google.com470e71d2011-07-07 08:21:25 +0000751void ViEEncoder::OnNetworkChanged(const WebRtc_Word32 id,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000752 const WebRtc_UWord32 bitrate_bps,
753 const WebRtc_UWord8 fraction_lost,
754 const WebRtc_UWord16 round_trip_time_ms) {
755 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
756 ViEId(engine_id_, channel_id_),
757 "%s(bitrate_bps: %u, fraction_lost: %u, rtt_ms: %u",
758 __FUNCTION__, bitrate_bps, fraction_lost, round_trip_time_ms);
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000759
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000760 vcm_.SetChannelParameters(bitrate_bps / 1000, fraction_lost,
761 round_trip_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000762}
763
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000764WebRtc_Word32 ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
765 CriticalSectionScoped cs(callback_critsect_);
766 if (effect_filter == NULL) {
767 if (effect_filter_ == NULL) {
768 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
769 ViEId(engine_id_, channel_id_), "%s: no effect filter added",
770 __FUNCTION__);
771 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000772 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000773 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
774 ViEId(engine_id_, channel_id_), "%s: deregister effect filter",
775 __FUNCTION__);
776 } else {
777 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
778 ViEId(engine_id_, channel_id_), "%s: register effect",
779 __FUNCTION__);
780 if (effect_filter_) {
781 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
782 ViEId(engine_id_, channel_id_),
783 "%s: effect filter already added ", __FUNCTION__);
784 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000786 }
787 effect_filter_ = effect_filter;
788 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000789}
790
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000791ViEFileRecorder& ViEEncoder::GetOutgoingFileRecorder() {
792 return file_recorder_;
793}
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000795QMTestVideoSettingsCallback::QMTestVideoSettingsCallback(
796 VideoProcessingModule* vpm,
797 VideoCodingModule* vcm,
798 WebRtc_Word32 num_cores,
799 WebRtc_Word32 max_payload_length)
800 : vpm_(vpm),
801 vcm_(vcm),
802 num_cores_(num_cores),
803 max_payload_length_(max_payload_length) {
804}
niklase@google.com470e71d2011-07-07 08:21:25 +0000805
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000806QMTestVideoSettingsCallback::~QMTestVideoSettingsCallback() {
807}
808
809WebRtc_Word32 QMTestVideoSettingsCallback::SetVideoQMSettings(
810 const WebRtc_UWord32 frame_rate,
811 const WebRtc_UWord32 width,
812 const WebRtc_UWord32 height) {
813 WebRtc_Word32 ret_val = 0;
814 ret_val = vpm_->SetTargetResolution(width, height, frame_rate);
815
816 if (!ret_val) {
817 // Get current settings.
818 VideoCodec current_codec;
819 vcm_->SendCodec(&current_codec);
820 WebRtc_UWord32 current_bit_rate = vcm_->Bitrate();
821
822 // Set the new calues.
823 current_codec.height = static_cast<WebRtc_UWord16>(height);
824 current_codec.width = static_cast<WebRtc_UWord16>(width);
825 current_codec.maxFramerate = static_cast<WebRtc_UWord8>(frame_rate);
826 current_codec.startBitrate = current_bit_rate;
827
828 // Re-register encoder with the updated settings.
829 ret_val = vcm_->RegisterSendCodec(&current_codec, num_cores_,
830 max_payload_length_);
831 }
832 return ret_val;
833}
834
835WebRtc_Word32 QMTestVideoSettingsCallback::SetMaxPayloadLength(
836 WebRtc_Word32 max_payload_length) {
837 max_payload_length_ = max_payload_length;
838}
839
840} // namespace webrtc