1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/video_coding/codec_database.h"
12
13#include <assert.h>
14
15#include "webrtc/base/checks.h"
16#include "webrtc/base/logging.h"
17#include "webrtc/engine_configurations.h"
18#include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
19#include "webrtc/modules/video_coding/codecs/i420/include/i420.h"
20#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
21#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
22#include "webrtc/modules/video_coding/internal_defines.h"
23
24namespace {
25const size_t kDefaultPayloadSize = 1440;
26const uint8_t kDefaultPayloadType = 100;
27}
28
29namespace webrtc {
30
31VideoCodecVP8 VideoEncoder::GetDefaultVp8Settings() {
32  VideoCodecVP8 vp8_settings;
33  memset(&vp8_settings, 0, sizeof(vp8_settings));
34
35  vp8_settings.resilience = kResilientStream;
36  vp8_settings.numberOfTemporalLayers = 1;
37  vp8_settings.denoisingOn = true;
38  vp8_settings.errorConcealmentOn = false;
39  vp8_settings.automaticResizeOn = false;
40  vp8_settings.frameDroppingOn = true;
41  vp8_settings.keyFrameInterval = 3000;
42
43  return vp8_settings;
44}
45
46VideoCodecVP9 VideoEncoder::GetDefaultVp9Settings() {
47  VideoCodecVP9 vp9_settings;
48  memset(&vp9_settings, 0, sizeof(vp9_settings));
49
50  vp9_settings.resilience = 1;
51  vp9_settings.numberOfTemporalLayers = 1;
52  vp9_settings.denoisingOn = false;
53  vp9_settings.frameDroppingOn = true;
54  vp9_settings.keyFrameInterval = 3000;
55  vp9_settings.adaptiveQpMode = true;
56  vp9_settings.automaticResizeOn = true;
57  vp9_settings.numberOfSpatialLayers = 1;
58  vp9_settings.flexibleMode = false;
59  return vp9_settings;
60}
61
62VideoCodecH264 VideoEncoder::GetDefaultH264Settings() {
63  VideoCodecH264 h264_settings;
64  memset(&h264_settings, 0, sizeof(h264_settings));
65
66  h264_settings.profile = kProfileBase;
67  h264_settings.frameDroppingOn = true;
68  h264_settings.keyFrameInterval = 3000;
69  h264_settings.spsData = nullptr;
70  h264_settings.spsLen = 0;
71  h264_settings.ppsData = nullptr;
72  h264_settings.ppsLen = 0;
73
74  return h264_settings;
75}
76
77VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
78                                     int number_of_cores,
79                                     bool require_key_frame)
80    : settings(settings),
81      number_of_cores(number_of_cores),
82      require_key_frame(require_key_frame) {
83  assert(number_of_cores >= 0);
84}
85
86VCMExtDecoderMapItem::VCMExtDecoderMapItem(
87    VideoDecoder* external_decoder_instance,
88    uint8_t payload_type)
89    : payload_type(payload_type),
90      external_decoder_instance(external_decoder_instance) {}
91
92VCMCodecDataBase::VCMCodecDataBase(
93    VideoEncoderRateObserver* encoder_rate_observer,
94    VCMEncodedFrameCallback* encoded_frame_callback)
95    : number_of_cores_(0),
96      max_payload_size_(kDefaultPayloadSize),
97      periodic_key_frames_(false),
98      pending_encoder_reset_(true),
99      send_codec_(),
100      receive_codec_(),
101      encoder_payload_type_(0),
102      external_encoder_(nullptr),
103      internal_source_(false),
104      encoder_rate_observer_(encoder_rate_observer),
105      encoded_frame_callback_(encoded_frame_callback),
106      ptr_decoder_(nullptr),
107      dec_map_(),
108      dec_external_map_() {}
109
110VCMCodecDataBase::~VCMCodecDataBase() {
111  DeleteEncoder();
112  ReleaseDecoder(ptr_decoder_);
113  for (auto& kv : dec_map_)
114    delete kv.second;
115  for (auto& kv : dec_external_map_)
116    delete kv.second;
117}
118
119void VCMCodecDataBase::Codec(VideoCodecType codec_type, VideoCodec* settings) {
120  memset(settings, 0, sizeof(VideoCodec));
121  switch (codec_type) {
122    case kVideoCodecVP8:
123      strncpy(settings->plName, "VP8", 4);
124      settings->codecType = kVideoCodecVP8;
125      // 96 to 127 dynamic payload types for video codecs.
126      settings->plType = kDefaultPayloadType;
127      settings->startBitrate = kDefaultStartBitrateKbps;
128      settings->minBitrate = VCM_MIN_BITRATE;
129      settings->maxBitrate = 0;
130      settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
131      settings->width = VCM_DEFAULT_CODEC_WIDTH;
132      settings->height = VCM_DEFAULT_CODEC_HEIGHT;
133      settings->numberOfSimulcastStreams = 0;
134      settings->qpMax = 56;
135      settings->codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
136      return;
137    case kVideoCodecVP9:
138      strncpy(settings->plName, "VP9", 4);
139      settings->codecType = kVideoCodecVP9;
140      // 96 to 127 dynamic payload types for video codecs.
141      settings->plType = kDefaultPayloadType;
142      settings->startBitrate = 100;
143      settings->minBitrate = VCM_MIN_BITRATE;
144      settings->maxBitrate = 0;
145      settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
146      settings->width = VCM_DEFAULT_CODEC_WIDTH;
147      settings->height = VCM_DEFAULT_CODEC_HEIGHT;
148      settings->numberOfSimulcastStreams = 0;
149      settings->qpMax = 56;
150      settings->codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
151      return;
152    case kVideoCodecH264:
153      strncpy(settings->plName, "H264", 5);
154      settings->codecType = kVideoCodecH264;
155      // 96 to 127 dynamic payload types for video codecs.
156      settings->plType = kDefaultPayloadType;
157      settings->startBitrate = kDefaultStartBitrateKbps;
158      settings->minBitrate = VCM_MIN_BITRATE;
159      settings->maxBitrate = 0;
160      settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
161      settings->width = VCM_DEFAULT_CODEC_WIDTH;
162      settings->height = VCM_DEFAULT_CODEC_HEIGHT;
163      settings->numberOfSimulcastStreams = 0;
164      settings->qpMax = 56;
165      settings->codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
166      return;
167    case kVideoCodecI420:
168      strncpy(settings->plName, "I420", 5);
169      settings->codecType = kVideoCodecI420;
170      // 96 to 127 dynamic payload types for video codecs.
171      settings->plType = kDefaultPayloadType;
172      // Bitrate needed for this size and framerate.
173      settings->startBitrate = 3 * VCM_DEFAULT_CODEC_WIDTH *
174                               VCM_DEFAULT_CODEC_HEIGHT * 8 *
175                               VCM_DEFAULT_FRAME_RATE / 1000 / 2;
176      settings->maxBitrate = settings->startBitrate;
177      settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
178      settings->width = VCM_DEFAULT_CODEC_WIDTH;
179      settings->height = VCM_DEFAULT_CODEC_HEIGHT;
180      settings->minBitrate = VCM_MIN_BITRATE;
181      settings->numberOfSimulcastStreams = 0;
182      return;
183    case kVideoCodecRED:
184    case kVideoCodecULPFEC:
185    case kVideoCodecGeneric:
186    case kVideoCodecUnknown:
187      RTC_NOTREACHED();
188      return;
189  }
190}
191
192// Assuming only one registered encoder - since only one used, no need for more.
193bool VCMCodecDataBase::SetSendCodec(const VideoCodec* send_codec,
194                                    int number_of_cores,
195                                    size_t max_payload_size) {
196  RTC_DCHECK(send_codec);
197  if (max_payload_size == 0) {
198    max_payload_size = kDefaultPayloadSize;
199  }
200  RTC_DCHECK_GE(number_of_cores, 1);
201  RTC_DCHECK_GE(send_codec->plType, 1);
202  // Make sure the start bit rate is sane...
203  RTC_DCHECK_LE(send_codec->startBitrate, 1000000u);
204  RTC_DCHECK(send_codec->codecType != kVideoCodecUnknown);
205  bool reset_required = pending_encoder_reset_;
206  if (number_of_cores_ != number_of_cores) {
207    number_of_cores_ = number_of_cores;
208    reset_required = true;
209  }
210  if (max_payload_size_ != max_payload_size) {
211    max_payload_size_ = max_payload_size;
212    reset_required = true;
213  }
214
215  VideoCodec new_send_codec;
216  memcpy(&new_send_codec, send_codec, sizeof(new_send_codec));
217
218  if (new_send_codec.maxBitrate == 0) {
219    // max is one bit per pixel
220    new_send_codec.maxBitrate = (static_cast<int>(send_codec->height) *
221                                 static_cast<int>(send_codec->width) *
222                                 static_cast<int>(send_codec->maxFramerate)) /
223                                1000;
224    if (send_codec->startBitrate > new_send_codec.maxBitrate) {
225      // But if the user tries to set a higher start bit rate we will
226      // increase the max accordingly.
227      new_send_codec.maxBitrate = send_codec->startBitrate;
228    }
229  }
230
231  if (new_send_codec.startBitrate > new_send_codec.maxBitrate)
232    new_send_codec.startBitrate = new_send_codec.maxBitrate;
233
234  if (!reset_required) {
235    reset_required = RequiresEncoderReset(new_send_codec);
236  }
237
238  memcpy(&send_codec_, &new_send_codec, sizeof(send_codec_));
239
240  if (!reset_required) {
241    encoded_frame_callback_->SetPayloadType(send_codec_.plType);
242    return true;
243  }
244
245  // If encoder exists, will destroy it and create new one.
246  DeleteEncoder();
247  RTC_DCHECK_EQ(encoder_payload_type_, send_codec_.plType)
248      << "Encoder not registered for payload type " << send_codec_.plType;
249  ptr_encoder_.reset(
250      new VCMGenericEncoder(external_encoder_, encoder_rate_observer_,
251                            encoded_frame_callback_, internal_source_));
252  encoded_frame_callback_->SetPayloadType(send_codec_.plType);
253  encoded_frame_callback_->SetInternalSource(internal_source_);
254  if (ptr_encoder_->InitEncode(&send_codec_, number_of_cores_,
255                               max_payload_size_) < 0) {
256    LOG(LS_ERROR) << "Failed to initialize video encoder.";
257    DeleteEncoder();
258    return false;
259  }
260
261  // Intentionally don't check return value since the encoder registration
262  // shouldn't fail because the codec doesn't support changing the periodic key
263  // frame setting.
264  ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_);
265
266  pending_encoder_reset_ = false;
267
268  return true;
269}
270
271bool VCMCodecDataBase::SendCodec(VideoCodec* current_send_codec) const {
272  if (!ptr_encoder_) {
273    return false;
274  }
275  memcpy(current_send_codec, &send_codec_, sizeof(VideoCodec));
276  return true;
277}
278
279VideoCodecType VCMCodecDataBase::SendCodec() const {
280  if (!ptr_encoder_) {
281    return kVideoCodecUnknown;
282  }
283  return send_codec_.codecType;
284}
285
286bool VCMCodecDataBase::DeregisterExternalEncoder(uint8_t payload_type,
287                                                 bool* was_send_codec) {
288  assert(was_send_codec);
289  *was_send_codec = false;
290  if (encoder_payload_type_ != payload_type) {
291    return false;
292  }
293  if (send_codec_.plType == payload_type) {
294    // De-register as send codec if needed.
295    DeleteEncoder();
296    memset(&send_codec_, 0, sizeof(VideoCodec));
297    *was_send_codec = true;
298  }
299  encoder_payload_type_ = 0;
300  external_encoder_ = nullptr;
301  internal_source_ = false;
302  return true;
303}
304
305void VCMCodecDataBase::RegisterExternalEncoder(VideoEncoder* external_encoder,
306                                               uint8_t payload_type,
307                                               bool internal_source) {
308  // Since only one encoder can be used at a given time, only one external
309  // encoder can be registered/used.
310  external_encoder_ = external_encoder;
311  encoder_payload_type_ = payload_type;
312  internal_source_ = internal_source;
313  pending_encoder_reset_ = true;
314}
315
316bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) {
317  if (!ptr_encoder_)
318    return true;
319
320  // Does not check startBitrate or maxFramerate
321  if (new_send_codec.codecType != send_codec_.codecType ||
322      strcmp(new_send_codec.plName, send_codec_.plName) != 0 ||
323      new_send_codec.plType != send_codec_.plType ||
324      new_send_codec.width != send_codec_.width ||
325      new_send_codec.height != send_codec_.height ||
326      new_send_codec.maxBitrate != send_codec_.maxBitrate ||
327      new_send_codec.minBitrate != send_codec_.minBitrate ||
328      new_send_codec.qpMax != send_codec_.qpMax ||
329      new_send_codec.numberOfSimulcastStreams !=
330          send_codec_.numberOfSimulcastStreams ||
331      new_send_codec.mode != send_codec_.mode ||
332      new_send_codec.extra_options != send_codec_.extra_options) {
333    return true;
334  }
335
336  switch (new_send_codec.codecType) {
337    case kVideoCodecVP8:
338      if (memcmp(&new_send_codec.codecSpecific.VP8,
339                 &send_codec_.codecSpecific.VP8,
340                 sizeof(new_send_codec.codecSpecific.VP8)) != 0) {
341        return true;
342      }
343      break;
344    case kVideoCodecVP9:
345      if (memcmp(&new_send_codec.codecSpecific.VP9,
346                 &send_codec_.codecSpecific.VP9,
347                 sizeof(new_send_codec.codecSpecific.VP9)) != 0) {
348        return true;
349      }
350      break;
351    case kVideoCodecH264:
352      if (memcmp(&new_send_codec.codecSpecific.H264,
353                 &send_codec_.codecSpecific.H264,
354                 sizeof(new_send_codec.codecSpecific.H264)) != 0) {
355        return true;
356      }
357      break;
358    case kVideoCodecGeneric:
359      break;
360    // Known codecs without payload-specifics
361    case kVideoCodecI420:
362    case kVideoCodecRED:
363    case kVideoCodecULPFEC:
364      break;
365    // Unknown codec type, reset just to be sure.
366    case kVideoCodecUnknown:
367      return true;
368  }
369
370  if (new_send_codec.numberOfSimulcastStreams > 0) {
371    for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams;
372         ++i) {
373      if (memcmp(&new_send_codec.simulcastStream[i],
374                 &send_codec_.simulcastStream[i],
375                 sizeof(new_send_codec.simulcastStream[i])) != 0) {
376        return true;
377      }
378    }
379  }
380  return false;
381}
382
383VCMGenericEncoder* VCMCodecDataBase::GetEncoder() {
384  return ptr_encoder_.get();
385}
386
387bool VCMCodecDataBase::SetPeriodicKeyFrames(bool enable) {
388  periodic_key_frames_ = enable;
389  if (ptr_encoder_) {
390    return (ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_) == 0);
391  }
392  return true;
393}
394
395bool VCMCodecDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
396  ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
397  if (it == dec_external_map_.end()) {
398    // Not found
399    return false;
400  }
401  // We can't use payload_type to check if the decoder is currently in use,
402  // because payload type may be out of date (e.g. before we decode the first
403  // frame after RegisterReceiveCodec)
404  if (ptr_decoder_ != nullptr &&
405      ptr_decoder_->_decoder == (*it).second->external_decoder_instance) {
406    // Release it if it was registered and in use.
407    ReleaseDecoder(ptr_decoder_);
408    ptr_decoder_ = nullptr;
409  }
410  DeregisterReceiveCodec(payload_type);
411  delete it->second;
412  dec_external_map_.erase(it);
413  return true;
414}
415
416// Add the external encoder object to the list of external decoders.
417// Won't be registered as a receive codec until RegisterReceiveCodec is called.
418void VCMCodecDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
419                                               uint8_t payload_type) {
420  // Check if payload value already exists, if so  - erase old and insert new.
421  VCMExtDecoderMapItem* ext_decoder =
422      new VCMExtDecoderMapItem(external_decoder, payload_type);
423  DeregisterExternalDecoder(payload_type);
424  dec_external_map_[payload_type] = ext_decoder;
425}
426
427bool VCMCodecDataBase::DecoderRegistered() const {
428  return !dec_map_.empty();
429}
430
431bool VCMCodecDataBase::RegisterReceiveCodec(const VideoCodec* receive_codec,
432                                            int number_of_cores,
433                                            bool require_key_frame) {
434  if (number_of_cores < 0) {
435    return false;
436  }
437  // Check if payload value already exists, if so  - erase old and insert new.
438  DeregisterReceiveCodec(receive_codec->plType);
439  if (receive_codec->codecType == kVideoCodecUnknown) {
440    return false;
441  }
442  VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
443  dec_map_[receive_codec->plType] = new VCMDecoderMapItem(
444      new_receive_codec, number_of_cores, require_key_frame);
445  return true;
446}
447
448bool VCMCodecDataBase::DeregisterReceiveCodec(uint8_t payload_type) {
449  DecoderMap::iterator it = dec_map_.find(payload_type);
450  if (it == dec_map_.end()) {
451    return false;
452  }
453  delete it->second;
454  dec_map_.erase(it);
455  if (receive_codec_.plType == payload_type) {
456    // This codec is currently in use.
457    memset(&receive_codec_, 0, sizeof(VideoCodec));
458  }
459  return true;
460}
461
462bool VCMCodecDataBase::ReceiveCodec(VideoCodec* current_receive_codec) const {
463  assert(current_receive_codec);
464  if (!ptr_decoder_) {
465    return false;
466  }
467  memcpy(current_receive_codec, &receive_codec_, sizeof(VideoCodec));
468  return true;
469}
470
471VideoCodecType VCMCodecDataBase::ReceiveCodec() const {
472  if (!ptr_decoder_) {
473    return kVideoCodecUnknown;
474  }
475  return receive_codec_.codecType;
476}
477
478VCMGenericDecoder* VCMCodecDataBase::GetDecoder(
479    const VCMEncodedFrame& frame,
480    VCMDecodedFrameCallback* decoded_frame_callback) {
481  uint8_t payload_type = frame.PayloadType();
482  if (payload_type == receive_codec_.plType || payload_type == 0) {
483    return ptr_decoder_;
484  }
485  // Check for exisitng decoder, if exists - delete.
486  if (ptr_decoder_) {
487    ReleaseDecoder(ptr_decoder_);
488    ptr_decoder_ = nullptr;
489    memset(&receive_codec_, 0, sizeof(VideoCodec));
490  }
491  ptr_decoder_ = CreateAndInitDecoder(frame, &receive_codec_);
492  if (!ptr_decoder_) {
493    return nullptr;
494  }
495  VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
496  if (callback)
497    callback->OnIncomingPayloadType(receive_codec_.plType);
498  if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) <
499      0) {
500    ReleaseDecoder(ptr_decoder_);
501    ptr_decoder_ = nullptr;
502    memset(&receive_codec_, 0, sizeof(VideoCodec));
503    return nullptr;
504  }
505  return ptr_decoder_;
506}
507
508void VCMCodecDataBase::ReleaseDecoder(VCMGenericDecoder* decoder) const {
509  if (decoder) {
510    assert(decoder->_decoder);
511    decoder->Release();
512    if (!decoder->External()) {
513      delete decoder->_decoder;
514    }
515    delete decoder;
516  }
517}
518
519bool VCMCodecDataBase::PrefersLateDecoding() const {
520  if (!ptr_decoder_)
521    return true;
522  return ptr_decoder_->PrefersLateDecoding();
523}
524
525bool VCMCodecDataBase::MatchesCurrentResolution(int width, int height) const {
526  return send_codec_.width == width && send_codec_.height == height;
527}
528
529VCMGenericDecoder* VCMCodecDataBase::CreateAndInitDecoder(
530    const VCMEncodedFrame& frame,
531    VideoCodec* new_codec) const {
532  uint8_t payload_type = frame.PayloadType();
533  assert(new_codec);
534  const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
535  if (!decoder_item) {
536    LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
537                  << static_cast<int>(payload_type);
538    return nullptr;
539  }
540  VCMGenericDecoder* ptr_decoder = nullptr;
541  const VCMExtDecoderMapItem* external_dec_item =
542      FindExternalDecoderItem(payload_type);
543  if (external_dec_item) {
544    // External codec.
545    ptr_decoder = new VCMGenericDecoder(
546        external_dec_item->external_decoder_instance, true);
547  } else {
548    // Create decoder.
549    ptr_decoder = CreateDecoder(decoder_item->settings->codecType);
550  }
551  if (!ptr_decoder)
552    return nullptr;
553
554  // Copy over input resolutions to prevent codec reinitialization due to
555  // the first frame being of a different resolution than the database values.
556  // This is best effort, since there's no guarantee that width/height have been
557  // parsed yet (and may be zero).
558  if (frame.EncodedImage()._encodedWidth > 0 &&
559      frame.EncodedImage()._encodedHeight > 0) {
560    decoder_item->settings->width = frame.EncodedImage()._encodedWidth;
561    decoder_item->settings->height = frame.EncodedImage()._encodedHeight;
562  }
563  if (ptr_decoder->InitDecode(decoder_item->settings.get(),
564                              decoder_item->number_of_cores) < 0) {
565    ReleaseDecoder(ptr_decoder);
566    return nullptr;
567  }
568  memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
569  return ptr_decoder;
570}
571
572void VCMCodecDataBase::DeleteEncoder() {
573  if (!ptr_encoder_)
574    return;
575  ptr_encoder_->Release();
576  ptr_encoder_.reset();
577}
578
579VCMGenericDecoder* VCMCodecDataBase::CreateDecoder(VideoCodecType type) const {
580  switch (type) {
581    case kVideoCodecVP8:
582      return new VCMGenericDecoder(VP8Decoder::Create());
583    case kVideoCodecVP9:
584      return new VCMGenericDecoder(VP9Decoder::Create());
585    case kVideoCodecI420:
586      return new VCMGenericDecoder(new I420Decoder());
587    case kVideoCodecH264:
588      if (H264Decoder::IsSupported()) {
589        return new VCMGenericDecoder(H264Decoder::Create());
590      }
591      break;
592    default:
593      break;
594  }
595  LOG(LS_WARNING) << "No internal decoder of this type exists.";
596  return nullptr;
597}
598
599const VCMDecoderMapItem* VCMCodecDataBase::FindDecoderItem(
600    uint8_t payload_type) const {
601  DecoderMap::const_iterator it = dec_map_.find(payload_type);
602  if (it != dec_map_.end()) {
603    return (*it).second;
604  }
605  return nullptr;
606}
607
608const VCMExtDecoderMapItem* VCMCodecDataBase::FindExternalDecoderItem(
609    uint8_t payload_type) const {
610  ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
611  if (it != dec_external_map_.end()) {
612    return (*it).second;
613  }
614  return nullptr;
615}
616}  // namespace webrtc
617