blob: 002f05cf50660c934f02a7b8af80c932280fce1c [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
11/*
12 * ViEEncoder.cpp
13 */
14
15#include "vie_encoder.h"
16#include "vie_defines.h"
17
18#include "critical_section_wrapper.h"
19#include "process_thread.h"
20#include "rtp_rtcp.h"
21#include "video_coding.h"
22#include "video_coding_defines.h"
23#include "video_codec_interface.h"
24#include "vie_codec.h"
25#include "vie_image_process.h"
26#include "tick_util.h"
27#include "trace.h"
28
29#include <cassert>
30namespace webrtc {
31
32// ----------------------------------------------------------------------------
33// Constructor
34// ----------------------------------------------------------------------------
35
36ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId,
37 WebRtc_UWord32 numberOfCores,
38 ProcessThread& moduleProcessThread)
39 :
40 _engineId(engineId),
41 _channelId(channelId),
42 _numberOfCores(numberOfCores),
43 _vcm(*webrtc::VideoCodingModule::Create(ViEModuleId(engineId,
44 channelId))),
45 _vpm(*webrtc::VideoProcessingModule::Create(ViEModuleId(engineId,
46 channelId))),
47 _rtpRtcp(*RtpRtcp::CreateRtpRtcp(ViEModuleId(engineId,
48 channelId),
49 false)),
50 _callbackCritsect(*CriticalSectionWrapper::CreateCriticalSection()),
51 _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()),
52 _paused(false), _timeLastIntraRequestMs(0),
53 _channelsDroppingDeltaFrames(0), _dropNextFrame(false),
54 _fecEnabled(false), _nackEnabled(false), _codecObserver(NULL),
55 _effectFilter(NULL), _moduleProcessThread(moduleProcessThread),
56 _hasReceivedSLI(false), _pictureIdSLI(0), _hasReceivedRPSI(false),
57 _pictureIdRPSI(0), _fileRecorder(channelId)
58{
59 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
60 ViEId(engineId, channelId),
61 "%s(engineId: %d) 0x%p - Constructor", __FUNCTION__, engineId,
62 this);
63
64 _vcm.InitializeSender();
65 _vpm.EnableTemporalDecimation(true);
66
67 // Enable/disable content analysis: off by default for now
68 _vpm.EnableContentAnalysis(false);
69
70 _moduleProcessThread.RegisterModule(&_vcm);
71 _rtpRtcp.InitSender();
72 _rtpRtcp.RegisterIncomingVideoCallback(this);
73 _rtpRtcp.RegisterIncomingRTCPCallback(this);
74 _moduleProcessThread.RegisterModule(&_rtpRtcp);
75
76 //
77 _qmCallback = new QMTestVideoSettingsCallback();
78 _qmCallback->RegisterVPM(&_vpm);
79 _qmCallback->RegisterVCM(&_vcm);
80 _qmCallback->SetNumOfCores(_numberOfCores);
81
82#ifdef VIDEOCODEC_VP8
83 VideoCodec videoCodec;
84 if (_vcm.Codec(webrtc::kVideoCodecVP8, &videoCodec) == VCM_OK)
85 {
86 _vcm.RegisterSendCodec(&videoCodec, _numberOfCores,
87 _rtpRtcp.MaxDataPayloadLength());
88 _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType);
89 }
90 else
91 {
92 assert(false);
93 }
94#else
95 VideoCodec videoCodec;
96 if (_vcm.Codec(webrtc::kVideoCodecI420, &videoCodec) == VCM_OK)
97 {
98 _vcm.RegisterSendCodec(&videoCodec, _numberOfCores,
99 _rtpRtcp.MaxDataPayloadLength());
100 _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType);
101 }
102 else
103 {
104 assert(false);
105 }
106#endif
107
108 if (_vcm.RegisterTransportCallback(this) != 0)
109 {
110 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
111 ViEId(_engineId, _channelId),
112 "%s: VCM::RegisterTransportCallback failure");
113 }
114 if (_vcm.RegisterSendStatisticsCallback(this) != 0)
115 {
116 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
117 ViEId(_engineId, _channelId),
118 "%s: VCM::RegisterSendStatisticsCallback failure");
119 }
120
121 if (_vcm.RegisterVideoQMCallback(_qmCallback) != 0)
122 {
123 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
124 ViEId(_engineId, _channelId),
125 "VCM::RegisterQMCallback failure");
126 }
127}
128
129// ----------------------------------------------------------------------------
130// Destructor
131// ----------------------------------------------------------------------------
132
133ViEEncoder::~ViEEncoder()
134{
135 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
136 ViEId(_engineId, _channelId),
137 "ViEEncoder Destructor 0x%p, engineId: %d", this, _engineId);
138
139 if (_rtpRtcp.NumberChildModules() > 0)
140 {
141 assert(false);
142 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
143 ViEId(_engineId, _channelId),
144 "Channels still attached %d, leaking memory",
145 _rtpRtcp.NumberChildModules());
146 return;
147 }
148 _moduleProcessThread.DeRegisterModule(&_vcm);
149 _moduleProcessThread.DeRegisterModule(&_vpm);
150 _moduleProcessThread.DeRegisterModule(&_rtpRtcp);
151 delete &_vcm;
152 delete &_vpm;
153 delete &_rtpRtcp;
154 delete &_callbackCritsect;
155 delete &_dataCritsect;
156}
157
158// ============================================================================
159// Start/Stop
160// ============================================================================
161
162// ----------------------------------------------------------------------------
163// Pause / Retart
164//
165// Call this to start/stop sending
166// ----------------------------------------------------------------------------
167
168void ViEEncoder::Pause()
169{
170 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
171 ViEId(_engineId, _channelId),
172 "%s", __FUNCTION__);
173 CriticalSectionScoped cs(_dataCritsect);
174 _paused = true;
175}
176
177void ViEEncoder::Restart()
178{
179 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
180 ViEId(_engineId, _channelId),
181 "%s", __FUNCTION__);
182 CriticalSectionScoped cs(_dataCritsect);
183 _paused = false;
184}
185
186// ----------------------------------------------------------------------------
187// DropDeltaAfterKey
188//
189// Drops the first delta frame after a key frame is encoded.
190// ----------------------------------------------------------------------------
191
192WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable)
193{
194 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
195 ViEId(_engineId, _channelId),
196 "%s(%d)", __FUNCTION__, enable);
197 CriticalSectionScoped cs(_dataCritsect);
198
199 if (enable)
200 {
201 _channelsDroppingDeltaFrames++;
202 } else
203 {
204 _channelsDroppingDeltaFrames--;
205 if (_channelsDroppingDeltaFrames < 0)
206 {
207 _channelsDroppingDeltaFrames = 0;
208 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
209 ViEId(_engineId, _channelId),
210 "%s: Called too many times", __FUNCTION__, enable);
211 return -1;
212 }
213 }
214 return 0;
215}
216
217// ============================================================================
218// Codec settigns
219// ============================================================================
220
221// ----------------------------------------------------------------------------
222// NumberOfCodecs
223// ----------------------------------------------------------------------------
224
225WebRtc_UWord8 ViEEncoder::NumberOfCodecs()
226{
227 return _vcm.NumberOfCodecs();
228}
229
230// ----------------------------------------------------------------------------
231// GetCodec
232// ----------------------------------------------------------------------------
233
234WebRtc_Word32 ViEEncoder::GetCodec(WebRtc_UWord8 listIndex,
235 webrtc::VideoCodec& videoCodec)
236{
237 if (_vcm.Codec(listIndex, &videoCodec) != 0)
238 {
239 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
240 ViEId(_engineId, _channelId), "%s: Could not get codec",
241 __FUNCTION__);
242 return -1;
243 }
244 return 0;
245}
246
247// ----------------------------------------------------------------------------
248// External encoder
249// ----------------------------------------------------------------------------
250WebRtc_Word32 ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
251 WebRtc_UWord8 plType)
252{
253 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
254 ViEId(_engineId, _channelId),
255 "%s: pltype %u", __FUNCTION__, plType);
256
257 if (encoder == NULL)
258 return -1;
259
260 if (_vcm.RegisterExternalEncoder(encoder, plType) != VCM_OK)
261 {
262 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
263 ViEId(_engineId, _channelId),
264 "Could not register external encoder");
265 return -1;
266 }
267 return 0;
268}
269
270WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 plType)
271{
272 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
273 ViEId(_engineId, _channelId),
274 "%s: pltype %u", __FUNCTION__, plType);
275
276 webrtc::VideoCodec currentSendCodec;
277 if (_vcm.SendCodec(&currentSendCodec) == VCM_OK)
278 {
279 currentSendCodec.startBitrate = _vcm.Bitrate();
280 }
281
282 if (_vcm.RegisterExternalEncoder(NULL, plType) != VCM_OK)
283 {
284 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
285 ViEId(_engineId, _channelId),
286 "Could not deregister external encoder");
287 return -1;
288 }
289
290 // If the external encoder is the current send codec use vcm internal encoder
291 if (currentSendCodec.plType == plType)
292 {
293 WebRtc_UWord16 maxDataPayloadLength = _rtpRtcp.MaxDataPayloadLength();
294 if (_vcm.RegisterSendCodec(&currentSendCodec, _numberOfCores,
295 maxDataPayloadLength) != VCM_OK)
296 {
297 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
298 ViEId(_engineId, _channelId),
299 "Could not use internal encoder");
300 return -1;
301 }
302 }
303 return 0;
304}
305
306// ----------------------------------------------------------------------------
307// SetEncoder
308// ----------------------------------------------------------------------------
309
310WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& videoCodec)
311{
312 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
313 ViEId(_engineId, _channelId),
314 "%s: CodecType: %d, width: %u, height: %u, maxPayloadLength: %u",
315 __FUNCTION__, videoCodec.codecType, videoCodec.width,
316 videoCodec.height);
317
318 // Multiply startBitrate by 1000 because RTP module changed in API.
319 if (_rtpRtcp.SetSendBitrate(videoCodec.startBitrate * 1000,
320 videoCodec.minBitrate, videoCodec.maxBitrate) != 0)
321 {
322 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
323 ViEId(_engineId, _channelId),
324 "Could not set RTP module bitrates");
325 return -1;
326 }
327
328 // Setting target width and height for VPM
329 if (_vpm.SetTargetResolution(videoCodec.width, videoCodec.height, videoCodec.maxFramerate) != VPM_OK)
330 {
331 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
332 ViEId(_engineId, _channelId),
333 "Could not set VPM target dimensions");
334 return -1;
335
336 }
337
338 if (_rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType) != 0)
339 {
340 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
341 ViEId(_engineId, _channelId),
342 "Could register RTP module video payload");
343 return -1;
344 }
345
346 WebRtc_UWord16 maxDataPayloadLength = _rtpRtcp.MaxDataPayloadLength();
347
348 // update QM with MaxDataPayloadLength
349 _qmCallback->SetMaxPayloadLength(maxDataPayloadLength);
350
351 if (_vcm.RegisterSendCodec(&videoCodec, _numberOfCores,
352 maxDataPayloadLength) != VCM_OK)
353 {
354 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
355 ViEId(_engineId, _channelId),
356 "Could not register send codec");
357 return -1;
358 }
359 _dataCritsect.Enter();
360 memcpy(&_sendCodec, &videoCodec, sizeof(_sendCodec)); // Copy current send codec
361 _dataCritsect.Leave();
362
363 // Set this module as sending right away, let the
364 // slave module in the channel start and stop sending...
365 if (_rtpRtcp.Sending() == false)
366 {
367 if (_rtpRtcp.SetSendingStatus(true) != 0)
368 {
369 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,
370 _channelId),
371 "Could start RTP module sending");
372 return -1;
373 }
374 }
375 return 0;
376}
377
378// ----------------------------------------------------------------------------
379// GetSendCodec
380// ----------------------------------------------------------------------------
381
382WebRtc_Word32 ViEEncoder::GetEncoder(webrtc::VideoCodec& videoCodec)
383{
384 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
385 "%s", __FUNCTION__);
386
387 if (_vcm.SendCodec(&videoCodec) != 0)
388 {
389 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
390 ViEId(_engineId, _channelId), "Could not get VCM send codec");
391 return -1;
392 }
393 return 0;
394}
395
396// ----------------------------------------------------------------------------
397// GetCodecConfigParameters
398//
399// Only valid for H.264 and MPEG-4
400// ----------------------------------------------------------------------------
401
402WebRtc_Word32 ViEEncoder::GetCodecConfigParameters(
403 unsigned char configParameters[kConfigParameterSize],
404 unsigned char& configParametersSize)
405{
406 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
407 "%s", __FUNCTION__);
408
409 WebRtc_Word32 numParameters =
410 _vcm.CodecConfigParameters(configParameters, kConfigParameterSize);
411 if (numParameters <= 0)
412 {
413 configParametersSize = 0;
414 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
415 ViEId(_engineId, _channelId),
416 "Could not get config parameters");
417 return -1;
418 }
419 configParametersSize = (unsigned char) numParameters;
420 return 0;
421}
422
423// ----------------------------------------------------------------------------
424// ScaleInputImage
425//
426// The input image will be scaled if the codec resolution differs from the
427// image resolution of the input image, otherwise will the image be
428// cropped/padded. Default: crop/pad.
429// ----------------------------------------------------------------------------
430
431WebRtc_Word32 ViEEncoder::ScaleInputImage(bool enable)
432{
433 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
434 "%s(enable %d)", __FUNCTION__, enable);
435
436 VideoFrameResampling resamplingMode = kFastRescaling;
437 if (enable == true)
438 {
439 // Currently not supported.
440 //resamplingMode = kInterpolation;
441 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
442 ViEId(_engineId, _channelId), "%s not supported",
443 __FUNCTION__, enable);
444 return -1;
445 }
446 _vpm.SetInputFrameResampleMode(resamplingMode);
447
448 return 0;
449}
450
451//=============================================================================
452// RTP settings
453//=============================================================================
454
455// ----------------------------------------------------------------------------
456// GetRtpRtcpModule
457// ----------------------------------------------------------------------------
458
459RtpRtcp* ViEEncoder::SendRtpRtcpModule()
460{
461 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
462 "%s", __FUNCTION__);
463
464 return &_rtpRtcp;
465}
466
467//=============================================================================
468// Data flow
469//=============================================================================
470
471
472// ----------------------------------------------------------------------------
473// DeliverFrame
474// Implements ViEFrameCallback::DeliverFrame
475// Receive videoFrame to be encoded from a provider (capture or file)
476// ----------------------------------------------------------------------------
477
478void ViEEncoder::DeliverFrame(int id, webrtc::VideoFrame& videoFrame,
479 int numCSRCs,
480 const WebRtc_UWord32 CSRC[kRtpCsrcSize])
481{
482 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
483 "%s: %llu", __FUNCTION__, videoFrame.TimeStamp());
484
485 {
486 CriticalSectionScoped cs(_dataCritsect);
487 if (_paused || _rtpRtcp.SendingMedia() == false)
488 {
489 // We've passed or we have no channels attached, don't encode
490 return;
491 }
492 if (_dropNextFrame)
493 {
494 // Drop this frame
495 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId,
496 _channelId),
497 "%s: Dropping frame %llu after a key fame",
498 __FUNCTION__, videoFrame.TimeStamp());
499 _dropNextFrame = false;
500 return;
501 }
502 }
503 // Set the frame timestamp
504 const WebRtc_UWord32 timeStamp = 90 * (WebRtc_UWord32) videoFrame.RenderTimeMs();
505 videoFrame.SetTimeStamp(timeStamp);
506 {
507 // Send to effect filter, if registered by user.
508 CriticalSectionScoped cs(_callbackCritsect);
509 if (_effectFilter)
510 {
511 _effectFilter->Transform(videoFrame.Length(), videoFrame.Buffer(),
512 videoFrame.TimeStamp(),
513 videoFrame.Width(), videoFrame.Height());
514 }
515 }
516 // Record un-encoded frame.
517 _fileRecorder.RecordVideoFrame(videoFrame);
518 // Make sure the CSRC list is correct.
519 if (numCSRCs > 0)
520 {
521 WebRtc_UWord32 tempCSRC[kRtpCsrcSize];
522 for (int i = 0; i < numCSRCs; i++)
523 {
524 if (CSRC[i] == 1)
525 {
526 tempCSRC[i] = _rtpRtcp.SSRC();
527 }
528 else
529 {
530 tempCSRC[i] = CSRC[i];
531 }
532 }
533 _rtpRtcp.SetCSRCs(tempCSRC, (WebRtc_UWord8) numCSRCs);
534 }
535
536#ifdef VIDEOCODEC_VP8
537 if (_vcm.SendCodec() == webrtc::kVideoCodecVP8)
538 {
539 webrtc::CodecSpecificInfo codecSpecificInfo;
540 codecSpecificInfo.codecType = webrtc::kVideoCodecUnknown;
541
542 if (_hasReceivedSLI || _hasReceivedRPSI)
543 {
544 webrtc::VideoCodec currentSendCodec;
545 _vcm.SendCodec(&currentSendCodec);
546 if (currentSendCodec.codecType == webrtc::kVideoCodecVP8)
547 {
548 codecSpecificInfo.codecType = webrtc::kVideoCodecVP8;
549 codecSpecificInfo.codecSpecific.VP8.hasReceivedRPSI = _hasReceivedRPSI;
550 codecSpecificInfo.codecSpecific.VP8.hasReceivedSLI = _hasReceivedSLI;
551 codecSpecificInfo.codecSpecific.VP8.pictureIdRPSI = _pictureIdRPSI;
552 codecSpecificInfo.codecSpecific.VP8.pictureIdSLI = _pictureIdSLI;
553 }
554 _hasReceivedSLI = false;
555 _hasReceivedRPSI = false;
556 }
557 // Pass frame via preprocessor
558 VideoFrame *decimatedFrame = NULL;
559 const int ret = _vpm.PreprocessFrame(&videoFrame, &decimatedFrame);
560 if (ret == 1)
561 {
562 // Drop this frame
563 return;
564 }
565 else if (ret != VPM_OK)
566 {
567 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
568 "%s: Error preprocessing frame %u", __FUNCTION__,
569 videoFrame.TimeStamp());
570 return;
571 }
572
573 VideoContentMetrics* contentMetrics = NULL;
574 contentMetrics = _vpm.ContentMetrics();
575
576 if (_vcm.AddVideoFrame
577 (*decimatedFrame, contentMetrics, &codecSpecificInfo) != VCM_OK)
578 {
579 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
580 "%s: Error encoding frame %u", __FUNCTION__,
581 videoFrame.TimeStamp());
582 }
583 return;
584 }
585#endif
586 // Pass frame via preprocessor
587 VideoFrame *decimatedFrame = NULL;
588 const int ret = _vpm.PreprocessFrame(&videoFrame, &decimatedFrame);
589 if (ret == 1)
590 {
591 // Drop this frame
592 return;
593 }
594 else if (ret != VPM_OK)
595 {
596 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
597 "%s: Error preprocessing frame %u", __FUNCTION__, videoFrame.TimeStamp());
598 return;
599 }
600 if (_vcm.AddVideoFrame(*decimatedFrame) != VCM_OK)
601 {
602 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
603 ViEId(_engineId, _channelId), "%s: Error encoding frame %u",
604 __FUNCTION__, videoFrame.TimeStamp());
605 }
606}
607// ----------------------------------------------------------------------------
608// DeliverFrame
609// Implements ViEFrameCallback::DelayChanged
610// ----------------------------------------------------------------------------
611void ViEEncoder::DelayChanged(int id, int frameDelay)
612
613{
614 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
615 "%s: %u", __FUNCTION__, frameDelay);
616
617 _rtpRtcp.SetCameraDelay(frameDelay);
618 _fileRecorder.SetFrameDelay(frameDelay);
619}
620// ----------------------------------------------------------------------------
621// GetPreferedFrameSettings
622// Implements ViEFrameCallback::GetPreferedFrameSettings
623// Fetch the widh, height and frame rate prefered by this encoder.
624// ----------------------------------------------------------------------------
625
626int ViEEncoder::GetPreferedFrameSettings(int &width, int &height,
627 int &frameRate)
628{
629 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
630 "%s", __FUNCTION__);
631
632 webrtc::VideoCodec videoCodec;
633 memset(&videoCodec, 0, sizeof(videoCodec));
634 if (_vcm.SendCodec(&videoCodec) != VCM_OK)
635 {
636 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
637 ViEId(_engineId, _channelId), "Could not get VCM send codec");
638 return -1;
639 }
640
641 width = videoCodec.width;
642 height = videoCodec.height;
643 frameRate = videoCodec.maxFramerate;
644 return 0;
645
646}
647// ----------------------------------------------------------------------------
648// SendKeyFrame
649// ----------------------------------------------------------------------------
650
651WebRtc_Word32 ViEEncoder::SendKeyFrame()
652{
653 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
654 "%s", __FUNCTION__);
655
656 return _vcm.FrameTypeRequest(kVideoFrameKey);
657}
658
659// ----------------------------------------------------------------------------
660// SendCodecStatistics
661// ----------------------------------------------------------------------------
662
663WebRtc_Word32 ViEEncoder::SendCodecStatistics(WebRtc_UWord32& numKeyFrames,
664 WebRtc_UWord32& numDeltaFrames)
665{
666 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
667 "%s", __FUNCTION__);
668
669 webrtc::VCMFrameCount sentFrames;
670 if (_vcm.SentFrameCount(sentFrames) != VCM_OK)
671 {
672 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
673 ViEId(_engineId, _channelId),
674 "%s: Could not get sent frame information", __FUNCTION__);
675 return -1;
676 }
677 numKeyFrames = sentFrames.numKeyFrames;
678 numDeltaFrames = sentFrames.numDeltaFrames;
679 return 0;
680
681}
682
683//=============================================================================
684// Loss protection
685//=============================================================================
686
687// ----------------------------------------------------------------------------
688// UpdateProtectionMethod
689//
690// Updated protection method to VCM to get correct packetization sizes
691// FEC has larger overhead than NACK -> set FEC if used
692// ----------------------------------------------------------------------------
693
694WebRtc_Word32 ViEEncoder::UpdateProtectionMethod()
695{
696 // Get FEC status
697 bool fecEnabled = false;
698 WebRtc_UWord8 dummyPTypeRed = 0;
699 WebRtc_UWord8 dummyPTypeFEC = 0;
700
701 // check if fec is enabled
702 WebRtc_Word32 error = _rtpRtcp.GenericFECStatus(fecEnabled, dummyPTypeRed,
703 dummyPTypeFEC);
704 if (error)
705 {
706 return -1;
707 }
708
709 // check if nack is enabled
710 bool nackEnabled = (_rtpRtcp.NACK() == kNackOff) ? false : true;
711 if (_fecEnabled == fecEnabled && _nackEnabled == nackEnabled)
712 {
713 // no change to current state
714 return 0;
715 }
716 _fecEnabled = fecEnabled;
717 _nackEnabled = nackEnabled;
718
719 // Set Video Protection for VCM
720 if (fecEnabled && nackEnabled)
721 {
722 _vcm.SetVideoProtection(webrtc::kProtectionNackFEC, true);
723 }
724 else
725 {
726 _vcm.SetVideoProtection(webrtc::kProtectionFEC, _fecEnabled);
727 _vcm.SetVideoProtection(webrtc::kProtectionNack, _nackEnabled);
728 _vcm.SetVideoProtection(webrtc::kProtectionNackFEC, false);
729 }
730
731 // If nack and/or fec is enalbed, the following should be triggered
732 if (fecEnabled || nackEnabled)
733 {
734 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
735 ViEId(_engineId, _channelId),
736 "%s: FEC status ", __FUNCTION__, fecEnabled);
737 _vcm.RegisterProtectionCallback(this);
738 // Need to reregister the send codec in order to set the new MTU
739 webrtc::VideoCodec codec;
740 if (_vcm.SendCodec(&codec) == 0)
741 {
742 WebRtc_UWord16 maxPayLoad = _rtpRtcp.MaxDataPayloadLength();
743 codec.startBitrate = _vcm.Bitrate();
744 if (_vcm.RegisterSendCodec(&codec, _numberOfCores, maxPayLoad) != 0)
745 {
746 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
747 ViEId(_engineId, _channelId),
748 "%s: Failed to update Sendcodec when enabling FEC",
749 __FUNCTION__, fecEnabled);
750 return -1;
751 }
752 }
753 return 0;
754 }
755 else
756 {
757 // FEC and NACK are disabled
758 _vcm.RegisterProtectionCallback(NULL);
759 }
760 return 0;
761}
762
763//=============================================================================
764// Implementation of VideoPacketizationCallback from VCM
765//=============================================================================
766
767// ----------------------------------------------------------------------------
768// SendData
769// ----------------------------------------------------------------------------
770WebRtc_Word32
771ViEEncoder::SendData(const FrameType frameType,
772 const WebRtc_UWord8 payloadType,
773 const WebRtc_UWord32 timeStamp,
774 const WebRtc_UWord8* payloadData,
775 const WebRtc_UWord32 payloadSize,
776 const webrtc::RTPFragmentationHeader& fragmentationHeader,
777 const RTPVideoTypeHeader* rtpTypeHdr)
778{
779 {
780 CriticalSectionScoped cs(_dataCritsect);
781 if (_paused)
782 {
783 // Paused, don't send this packet
784 return 0;
785 }
786 if (_channelsDroppingDeltaFrames && frameType == webrtc::kVideoFrameKey)
787 {
788 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId,
789 _channelId),
790 "%s: Sending key frame, drop next frame", __FUNCTION__);
791 _dropNextFrame = true;
792 }
793 }
794 // New encoded data, hand over to the rtp module
795 WebRtc_Word32 retVal = _rtpRtcp.SendOutgoingData(frameType, payloadType,
796 timeStamp, payloadData,
797 payloadSize,
798 &fragmentationHeader,
799 rtpTypeHdr);
800 return retVal;
801}
802
803//=============================================================================
804// Implementation of VideoProtectionCallback from VCM
805//=============================================================================
806
807// ----------------------------------------------------------------------------
808// ProtectionRequest
809// ----------------------------------------------------------------------------
810
811WebRtc_Word32 ViEEncoder::ProtectionRequest(const WebRtc_UWord8 deltaFECRate,
812 const WebRtc_UWord8 keyFECRate,
813 const bool nack)
814{
815 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
816 "%s: deltaFECRate: %u, keyFECRate: %u, nack: %d", __FUNCTION__,
817 deltaFECRate, keyFECRate, nack);
818
819 if (_rtpRtcp.SetFECCodeRate(keyFECRate, deltaFECRate) != 0)
820 {
821 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
822 ViEId(_engineId, _channelId),
823 "%s: Could not update FEC code rate", __FUNCTION__);
824 }
825 return 0;
826}
827
828//=============================================================================
829// Implementation of VideoSendStatisticsCallback from VCM
830//=============================================================================
831
832// ----------------------------------------------------------------------------
833// SendStatistics
834// ----------------------------------------------------------------------------
835
836WebRtc_Word32 ViEEncoder::SendStatistics(const WebRtc_UWord32 bitRate,
837 const WebRtc_UWord32 frameRate)
838{
839 CriticalSectionScoped cs(_callbackCritsect);
840 if (_codecObserver)
841 {
842 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
843 "%s: bitrate %u, framerate %u", __FUNCTION__, bitRate,
844 frameRate);
845 _codecObserver->OutgoingRate(_channelId, frameRate, bitRate);
846 }
847 return 0;
848}
849
850// ----------------------------------------------------------------------------
851// RegisterCodecObserver
852// ----------------------------------------------------------------------------
853
854WebRtc_Word32 ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer)
855{
856 CriticalSectionScoped cs(_callbackCritsect);
857 if (observer)
858 {
859 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
860 "%s: observer added", __FUNCTION__);
861 if (_codecObserver)
862 {
863 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,
864 _channelId),
865 "%s: observer already set.", __FUNCTION__);
866 return -1;
867 }
868 _codecObserver = observer;
869 } else
870 {
871 if (_codecObserver == NULL)
872 {
873 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId,
874 _channelId),
875 "%s: observer does not exist.", __FUNCTION__);
876 return -1;
877 }
878 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
879 "%s: observer removed", __FUNCTION__);
880 _codecObserver = NULL;
881 }
882 return 0;
883}
884
885//=============================================================================
886// Implementation of RtcpFeedback
887//=============================================================================
888
889void ViEEncoder::OnSLIReceived(const WebRtc_Word32 id,
890 const WebRtc_UWord8 pictureId)
891{
892 _pictureIdSLI = pictureId;
893 _hasReceivedSLI = true;
894}
895
896void ViEEncoder::OnRPSIReceived(const WebRtc_Word32 id,
897 const WebRtc_UWord64 pictureId)
898{
899 _pictureIdRPSI = pictureId;
900 _hasReceivedRPSI = true;
901}
902
903//=============================================================================
904// Implementation of RtpVideoFeedback
905//=============================================================================
906
907// ----------------------------------------------------------------------------
908// OnReceivedIntraFrameRequest
909// ----------------------------------------------------------------------------
910
911void ViEEncoder::OnReceivedIntraFrameRequest(const WebRtc_Word32 id,
912 const WebRtc_UWord8 message)
913{
914 // Key frame request from other side, signal to VCM
915 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
916 "%s", __FUNCTION__);
917
918 if (_timeLastIntraRequestMs + kViEMinKeyRequestIntervalMs
919 > TickTime::MillisecondTimestamp())
920 {
921 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
922 ViEId(_engineId, _channelId),
923 "%s: Not not encoding new intra due to timing", __FUNCTION__);
924 return;
925 }
926 // Default message == 0...
927 if (message == 0)
928 {
929 _vcm.FrameTypeRequest(kVideoFrameKey);
930 } else
931 {
932 _vcm.FrameTypeRequest((FrameType) message);
933 }
934 _timeLastIntraRequestMs = TickTime::MillisecondTimestamp();
935 return;
936}
937
938// ----------------------------------------------------------------------------
939// OnNetworkChanged
940// ----------------------------------------------------------------------------
941void ViEEncoder::OnNetworkChanged(const WebRtc_Word32 id,
942 const WebRtc_UWord32 minBitrateBps,
943 const WebRtc_UWord32 maxBitrateBps,
944 const WebRtc_UWord8 fractionLost,
945 const WebRtc_UWord16 roundTripTimeMs,
946 const WebRtc_UWord16 bwEstimateKbitMin,
947 const WebRtc_UWord16 bwEstimateKbitMax)
948{
949 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
950 "%s(minBitrateBps: %u, maxBitrateBps: %u,fractionLost: %u, rttMs: %u, bwEstMinKbit: %u, bwEstMaxKbit: %u",
951 __FUNCTION__, minBitrateBps, maxBitrateBps, fractionLost,
952 roundTripTimeMs, bwEstimateKbitMin, bwEstimateKbitMax);
953 _vcm.SetChannelParameters(minBitrateBps / 1000, fractionLost, roundTripTimeMs);
954 return;
955}
956
957WebRtc_Word32 ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effectFilter)
958{
959 CriticalSectionScoped cs(_callbackCritsect);
960 if (effectFilter == NULL)
961 {
962 if (_effectFilter == NULL)
963 {
964 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,
965 _channelId),
966 "%s: no effect filter added", __FUNCTION__);
967 return -1;
968 }
969 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
970 "%s: deregister effect filter", __FUNCTION__);
971 } else
972 {
973 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId),
974 "%s: register effect", __FUNCTION__);
975 if (_effectFilter)
976 {
977 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,
978 _channelId),
979 "%s: effect filter already added ", __FUNCTION__);
980 return -1;
981 }
982 }
983 _effectFilter = effectFilter;
984 return 0;
985}
986
987ViEFileRecorder& ViEEncoder::GetOutgoingFileRecorder()
988{
989 return _fileRecorder;
990}
991
992//=============================================================================
993// Implementation of Video QM settings callback:
994// Callback to be called from VCM to update VPM of frame rate and size
995//=============================================================================
996
997ViEEncoder::QMTestVideoSettingsCallback::QMTestVideoSettingsCallback():
998_vpm(NULL),
999_vcm(NULL)
1000{
1001
1002}
1003
1004void ViEEncoder::QMTestVideoSettingsCallback::
1005 RegisterVPM(VideoProcessingModule *vpm)
1006{
1007 _vpm = vpm;
1008}
1009
1010void ViEEncoder::QMTestVideoSettingsCallback::
1011 RegisterVCM(VideoCodingModule *vcm)
1012{
1013 _vcm = vcm;
1014}
1015
1016WebRtc_Word32 ViEEncoder::QMTestVideoSettingsCallback::SetVideoQMSettings
1017 (const WebRtc_UWord32 frameRate,
1018 const WebRtc_UWord32 width,
1019 const WebRtc_UWord32 height)
1020{
1021
1022 WebRtc_Word32 retVal = 0;
1023 retVal = _vpm->SetTargetResolution(width, height, frameRate);
1024 //Initialize codec with new values
1025 if (!retVal)
1026 {
1027 // first get current settings
1028 VideoCodec currentCodec;
1029 _vcm->SendCodec(&currentCodec);
1030
1031 WebRtc_UWord32 currentBitRate = _vcm->Bitrate();
1032
1033 // now set new values:
1034 currentCodec.height = (WebRtc_UWord16)height;
1035 currentCodec.width = (WebRtc_UWord16)width;
1036 currentCodec.maxFramerate = (WebRtc_UWord8)frameRate;
1037 currentCodec.startBitrate = currentBitRate;
1038
1039 // re-register encoder
1040 retVal = _vcm->RegisterSendCodec(&currentCodec,_numOfCores,_maxPayloadLength);
1041 }
1042
1043 return retVal;
1044}
1045
1046/////////////////////
1047
1048
1049} // namespace webrtc