tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebrtcMediaDataEncoderCodec.cpp (20623B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "WebrtcMediaDataEncoderCodec.h"
      6 
      7 #include <utility>
      8 
      9 #include "AnnexB.h"
     10 #include "ImageContainer.h"
     11 #include "MediaData.h"
     12 #include "PEMFactory.h"
     13 #include "VideoUtils.h"
     14 #include "api/video_codecs/h264_profile_level_id.h"
     15 #include "media/base/media_constants.h"
     16 #include "modules/video_coding/utility/vp8_header_parser.h"
     17 #include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
     18 #include "mozilla/Assertions.h"
     19 #include "mozilla/Maybe.h"
     20 #include "mozilla/StaticPrefs_media.h"
     21 #include "mozilla/gfx/Point.h"
     22 #include "mozilla/media/MediaUtils.h"
     23 
     24 namespace mozilla {
     25 
     26 extern LazyLogModule sPEMLog;
     27 
     28 #undef LOG
     29 #define LOG(msg, ...)               \
     30  MOZ_LOG(sPEMLog, LogLevel::Debug, \
     31          ("WebrtcMediaDataEncoder=%p, " msg, this, ##__VA_ARGS__))
     32 
     33 #undef LOG_V
     34 #define LOG_V(msg, ...)               \
     35  MOZ_LOG(sPEMLog, LogLevel::Verbose, \
     36          ("WebrtcMediaDataEncoder=%p, " msg, this, ##__VA_ARGS__))
     37 
     38 using namespace media;
     39 using namespace layers;
     40 
     41 CodecType ConvertWebrtcCodecTypeToCodecType(
     42    const webrtc::VideoCodecType& aType) {
     43  switch (aType) {
     44    case webrtc::VideoCodecType::kVideoCodecVP8:
     45      return CodecType::VP8;
     46    case webrtc::VideoCodecType::kVideoCodecVP9:
     47      return CodecType::VP9;
     48    case webrtc::VideoCodecType::kVideoCodecH264:
     49      return CodecType::H264;
     50    case webrtc::VideoCodecType::kVideoCodecAV1:
     51      return CodecType::AV1;
     52    case webrtc::VideoCodecType::kVideoCodecGeneric:
     53    case webrtc::VideoCodecType::kVideoCodecH265:
     54      return CodecType::Unknown;
     55  }
     56  MOZ_CRASH("Unsupported codec type");
     57  return CodecType::Unknown;
     58 }
     59 
     60 bool WebrtcMediaDataEncoder::CanCreate(
     61    const webrtc::VideoCodecType aCodecType) {
     62  if (aCodecType != webrtc::VideoCodecType::kVideoCodecH264 &&
     63      aCodecType != webrtc::VideoCodecType::kVideoCodecVP8 &&
     64      aCodecType != webrtc::VideoCodecType::kVideoCodecVP9) {
     65    // TODO: Bug 1980201 - Add support for remaining codecs (e.g. AV1, HEVC).
     66    return false;
     67  }
     68  auto factory = MakeRefPtr<PEMFactory>();
     69  CodecType type = ConvertWebrtcCodecTypeToCodecType(aCodecType);
     70  return !factory->SupportsCodec(type).isEmpty();
     71 }
     72 
     73 static const char* PacketModeStr(const webrtc::CodecSpecificInfo& aInfo) {
     74  MOZ_ASSERT(aInfo.codecType != webrtc::VideoCodecType::kVideoCodecGeneric);
     75 
     76  if (aInfo.codecType != webrtc::VideoCodecType::kVideoCodecH264) {
     77    return "N/A";
     78  }
     79  switch (aInfo.codecSpecific.H264.packetization_mode) {
     80    case webrtc::H264PacketizationMode::SingleNalUnit:
     81      return "SingleNalUnit";
     82    case webrtc::H264PacketizationMode::NonInterleaved:
     83      return "NonInterleaved";
     84    default:
     85      return "Unknown";
     86  }
     87 }
     88 
     89 static std::pair<H264_PROFILE, H264_LEVEL> ConvertProfileLevel(
     90    const webrtc::CodecParameterMap& aParameters) {
     91  const std::optional<webrtc::H264ProfileLevelId> profileLevel =
     92      webrtc::ParseSdpForH264ProfileLevelId(aParameters);
     93 
     94  if (!profileLevel) {
     95    // TODO: Eveluate if there is a better default setting.
     96    return std::make_pair(H264_PROFILE::H264_PROFILE_MAIN,
     97                          H264_LEVEL::H264_LEVEL_3_1);
     98  }
     99 
    100  H264_PROFILE profile =
    101      (profileLevel->profile == webrtc::H264Profile::kProfileBaseline ||
    102       profileLevel->profile ==
    103           webrtc::H264Profile::kProfileConstrainedBaseline)
    104          ? H264_PROFILE::H264_PROFILE_BASE
    105          : H264_PROFILE::H264_PROFILE_MAIN;
    106  // H264Level::kLevel1_b cannot be mapped to H264_LEVEL::H264_LEVEL_1_b by
    107  // value directly since their values are different.
    108  H264_LEVEL level =
    109      profileLevel->level == webrtc::H264Level::kLevel1_b
    110          ? H264_LEVEL::H264_LEVEL_1_b
    111          : static_cast<H264_LEVEL>(static_cast<int>(profileLevel->level));
    112 
    113  return std::make_pair(profile, level);
    114 }
    115 
    116 static VPXComplexity MapComplexity(webrtc::VideoCodecComplexity aComplexity) {
    117  switch (aComplexity) {
    118    case webrtc::VideoCodecComplexity::kComplexityNormal:
    119      return VPXComplexity::Normal;
    120    case webrtc::VideoCodecComplexity::kComplexityHigh:
    121      return VPXComplexity::High;
    122    case webrtc::VideoCodecComplexity::kComplexityHigher:
    123      return VPXComplexity::Higher;
    124    case webrtc::VideoCodecComplexity::kComplexityMax:
    125      return VPXComplexity::Max;
    126    default:
    127      MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad complexity value");
    128  }
    129 }
    130 
    131 WebrtcMediaDataEncoder::WebrtcMediaDataEncoder(
    132    const webrtc::SdpVideoFormat& aFormat)
    133    : mTaskQueue(
    134          TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
    135                            "WebrtcMediaDataEncoder::mTaskQueue")),
    136      mFactory(new PEMFactory()),
    137      mCallbackMutex("WebrtcMediaDataEncoderCodec encoded callback mutex"),
    138      mFormatParams(aFormat.parameters),
    139      // Use the same lower and upper bound as h264_video_toolbox_encoder which
    140      // is an encoder from webrtc's upstream codebase.
    141      // 0.5 is set as a mininum to prevent overcompensating for large temporary
    142      // overshoots. We don't want to degrade video quality too badly.
    143      // 0.95 is set to prevent oscillations. When a lower bitrate is set on the
    144      // encoder than previously set, its output seems to have a brief period of
    145      // drastically reduced bitrate, so we want to avoid that. In steady state
    146      // conditions, 0.95 seems to give us better overall bitrate over long
    147      // periods of time.
    148      mBitrateAdjuster(0.5, 0.95) {
    149  PodZero(&mCodecSpecific.codecSpecific);
    150 }
    151 
    152 WebrtcMediaDataEncoder::~WebrtcMediaDataEncoder() {
    153  if (mEncoder) {
    154    Shutdown();
    155  }
    156 }
    157 
    158 static void InitCodecSpecficInfo(webrtc::CodecSpecificInfo& aInfo,
    159                                 const webrtc::VideoCodec* aCodecSettings,
    160                                 const webrtc::CodecParameterMap& aParameters) {
    161  MOZ_ASSERT(aCodecSettings);
    162 
    163  aInfo.codecType = aCodecSettings->codecType;
    164  switch (aCodecSettings->codecType) {
    165    case webrtc::VideoCodecType::kVideoCodecH264: {
    166      aInfo.codecSpecific.H264.packetization_mode =
    167          aParameters.count(webrtc::kH264FmtpPacketizationMode) == 1 &&
    168                  aParameters.at(webrtc::kH264FmtpPacketizationMode) == "1"
    169              ? webrtc::H264PacketizationMode::NonInterleaved
    170              : webrtc::H264PacketizationMode::SingleNalUnit;
    171      break;
    172    }
    173    case webrtc::VideoCodecType::kVideoCodecVP9: {
    174      MOZ_ASSERT(aCodecSettings->VP9().numberOfSpatialLayers == 1);
    175      aInfo.codecSpecific.VP9.flexible_mode =
    176          aCodecSettings->VP9().flexibleMode;
    177      aInfo.codecSpecific.VP9.first_frame_in_picture = true;
    178      break;
    179    }
    180    default:
    181      break;
    182  }
    183 }
    184 
    185 int32_t WebrtcMediaDataEncoder::InitEncode(
    186    const webrtc::VideoCodec* aCodecSettings,
    187    const webrtc::VideoEncoder::Settings& aSettings) {
    188  MOZ_ASSERT(aCodecSettings);
    189 
    190  if (aCodecSettings->numberOfSimulcastStreams > 1) {
    191    LOG("Only one stream is supported. Falling back to simulcast adaptor");
    192    return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED;
    193  }
    194 
    195  // TODO: enable max output size setting when supported.
    196  if (aCodecSettings->codecType == webrtc::VideoCodecType::kVideoCodecH264 &&
    197      !(mFormatParams.count(webrtc::kH264FmtpPacketizationMode) == 1 &&
    198        mFormatParams.at(webrtc::kH264FmtpPacketizationMode) == "1")) {
    199    LOG("Some platform encoders don't support setting max output size."
    200        " Falling back to SW");
    201    return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
    202  }
    203 
    204  if (mEncoder) {
    205    // Clean existing encoder.
    206    Shutdown();
    207  }
    208 
    209  RefPtr<MediaDataEncoder> encoder = CreateEncoder(aCodecSettings);
    210  if (!encoder) {
    211    LOG("Fail to create encoder. Falling back to SW");
    212    return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
    213  }
    214 
    215  InitCodecSpecficInfo(mCodecSpecific, aCodecSettings, mFormatParams);
    216  LOG("Init encode, mimeType %s, mode %s", mInfo.mMimeType.get(),
    217      PacketModeStr(mCodecSpecific));
    218  if (!media::Await(do_AddRef(mTaskQueue), encoder->Init()).IsResolve()) {
    219    LOG("Fail to init encoder. Falling back to SW");
    220    return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
    221  }
    222  mEncoder = std::move(encoder);
    223  return WEBRTC_VIDEO_CODEC_OK;
    224 }
    225 
    226 bool WebrtcMediaDataEncoder::SetupConfig(
    227    const webrtc::VideoCodec* aCodecSettings) {
    228  mMaxFrameRate = aCodecSettings->maxFramerate;
    229  // Those bitrates in codec setting are all kbps, so we have to covert them to
    230  // bps.
    231  mMaxBitrateBps = aCodecSettings->maxBitrate * 1000;
    232  mMinBitrateBps = aCodecSettings->minBitrate * 1000;
    233  mBitrateAdjuster.SetTargetBitrateBps(aCodecSettings->startBitrate * 1000);
    234  return true;
    235 }
    236 
    237 already_AddRefed<MediaDataEncoder> WebrtcMediaDataEncoder::CreateEncoder(
    238    const webrtc::VideoCodec* aCodecSettings) {
    239  if (!SetupConfig(aCodecSettings)) {
    240    return nullptr;
    241  }
    242  LOG("Request platform encoder for %s, bitRate=%u bps, frameRate=%u",
    243      mInfo.mMimeType.get(), mBitrateAdjuster.GetTargetBitrateBps(),
    244      aCodecSettings->maxFramerate);
    245 
    246  size_t keyframeInterval = 1;
    247  switch (aCodecSettings->codecType) {
    248    case webrtc::VideoCodecType::kVideoCodecH264: {
    249      keyframeInterval = aCodecSettings->H264().keyFrameInterval;
    250      break;
    251    }
    252    case webrtc::VideoCodecType::kVideoCodecVP8: {
    253      keyframeInterval = aCodecSettings->VP8().keyFrameInterval;
    254      break;
    255    }
    256    case webrtc::VideoCodecType::kVideoCodecVP9: {
    257      keyframeInterval = aCodecSettings->VP9().keyFrameInterval;
    258      break;
    259    }
    260    default:
    261      MOZ_ASSERT_UNREACHABLE("Unsupported codec type");
    262      return nullptr;
    263  }
    264 
    265  CodecType type;
    266  EncoderConfig::CodecSpecific specific{void_t{}};
    267  switch (aCodecSettings->codecType) {
    268    case webrtc::VideoCodecType::kVideoCodecH264: {
    269      type = CodecType::H264;
    270      std::pair<H264_PROFILE, H264_LEVEL> profileLevel =
    271          ConvertProfileLevel(mFormatParams);
    272      specific.emplace<H264Specific>(profileLevel.first, profileLevel.second,
    273                                     H264BitStreamFormat::ANNEXB);
    274      break;
    275    }
    276    case webrtc::VideoCodecType::kVideoCodecVP8: {
    277      type = CodecType::VP8;
    278      const webrtc::VideoCodecVP8& vp8 = aCodecSettings->VP8();
    279      const webrtc::VideoCodecComplexity complexity =
    280          aCodecSettings->GetVideoEncoderComplexity();
    281      const bool frameDropEnabled = aCodecSettings->GetFrameDropEnabled();
    282      specific.emplace<VP8Specific>(MapComplexity(complexity), false,
    283                                    vp8.numberOfTemporalLayers, vp8.denoisingOn,
    284                                    vp8.automaticResizeOn, frameDropEnabled);
    285      break;
    286    }
    287    case webrtc::VideoCodecType::kVideoCodecVP9: {
    288      type = CodecType::VP9;
    289      const webrtc::VideoCodecVP9& vp9 = aCodecSettings->VP9();
    290      const webrtc::VideoCodecComplexity complexity =
    291          aCodecSettings->GetVideoEncoderComplexity();
    292      const bool frameDropEnabled = aCodecSettings->GetFrameDropEnabled();
    293      specific.emplace<VP9Specific>(
    294          MapComplexity(complexity), false, vp9.numberOfTemporalLayers,
    295          vp9.denoisingOn, vp9.automaticResizeOn, frameDropEnabled,
    296          vp9.adaptiveQpMode, vp9.numberOfSpatialLayers, vp9.flexibleMode);
    297      break;
    298    }
    299    default:
    300      MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unsupported codec type");
    301  }
    302  EncoderConfig config(
    303      type, {aCodecSettings->width, aCodecSettings->height}, Usage::Realtime,
    304      EncoderConfig::SampleFormat(dom::ImageBitmapFormat::YUV420P),
    305      aCodecSettings->maxFramerate, keyframeInterval,
    306      mBitrateAdjuster.GetTargetBitrateBps(), mMinBitrateBps, mMaxBitrateBps,
    307      BitrateMode::Variable, HardwarePreference::None, ScalabilityMode::None,
    308      specific);
    309  return mFactory->CreateEncoder(config, mTaskQueue);
    310 }
    311 
    312 WebrtcVideoEncoder::EncoderInfo WebrtcMediaDataEncoder::GetEncoderInfo() const {
    313  WebrtcVideoEncoder::EncoderInfo info;
    314  info.supports_native_handle = false;
    315  info.implementation_name = "MediaDataEncoder";
    316  info.is_hardware_accelerated = false;
    317  info.supports_simulcast = false;
    318 
    319 #ifdef MOZ_WIDGET_ANDROID
    320  // Assume MediaDataEncoder is used mainly for hardware encoding. 16-alignment
    321  // seems required on Android. This could be improved by querying the
    322  // underlying encoder.
    323  info.requested_resolution_alignment = 16;
    324  info.apply_alignment_to_all_simulcast_layers = true;
    325 #endif
    326  return info;
    327 }
    328 
    329 int32_t WebrtcMediaDataEncoder::RegisterEncodeCompleteCallback(
    330    webrtc::EncodedImageCallback* aCallback) {
    331  MutexAutoLock lock(mCallbackMutex);
    332  mCallback = aCallback;
    333  return WEBRTC_VIDEO_CODEC_OK;
    334 }
    335 
    336 int32_t WebrtcMediaDataEncoder::Shutdown() {
    337  LOG("Release encoder");
    338  {
    339    MutexAutoLock lock(mCallbackMutex);
    340    mCallback = nullptr;
    341    mError = NS_OK;
    342  }
    343  if (mEncoder) {
    344    media::Await(do_AddRef(mTaskQueue), mEncoder->Shutdown());
    345    mEncoder = nullptr;
    346  }
    347  return WEBRTC_VIDEO_CODEC_OK;
    348 }
    349 
    350 static already_AddRefed<VideoData> CreateVideoDataFromWebrtcVideoFrame(
    351    const webrtc::VideoFrame& aFrame, const bool aIsKeyFrame,
    352    const TimeUnit aDuration) {
    353  MOZ_ASSERT(aFrame.video_frame_buffer()->type() ==
    354                 webrtc::VideoFrameBuffer::Type::kI420,
    355             "Only support YUV420!");
    356  const webrtc::I420BufferInterface* i420 =
    357      aFrame.video_frame_buffer()->GetI420();
    358 
    359  PlanarYCbCrData yCbCrData;
    360  yCbCrData.mYChannel = const_cast<uint8_t*>(i420->DataY());
    361  yCbCrData.mYStride = i420->StrideY();
    362  yCbCrData.mCbChannel = const_cast<uint8_t*>(i420->DataU());
    363  yCbCrData.mCrChannel = const_cast<uint8_t*>(i420->DataV());
    364  MOZ_ASSERT(i420->StrideU() == i420->StrideV());
    365  yCbCrData.mCbCrStride = i420->StrideU();
    366  yCbCrData.mPictureRect = gfx::IntRect(0, 0, i420->width(), i420->height());
    367  yCbCrData.mChromaSubsampling = gfx::ChromaSubsampling::HALF_WIDTH_AND_HEIGHT;
    368 
    369  RefPtr<PlanarYCbCrImage> image =
    370      new RecyclingPlanarYCbCrImage(new BufferRecycleBin());
    371  image->CopyData(yCbCrData);
    372 
    373  // Although webrtc::VideoFrame::timestamp_rtp_ will likely be deprecated,
    374  // webrtc::EncodedImage and the VPx encoders still use it in the imported
    375  // version of libwebrtc. Not using the same timestamp values generates
    376  // discontinuous time and confuses the video receiver when switching from
    377  // platform to libwebrtc encoder.
    378  TimeUnit timestamp =
    379      media::TimeUnit(aFrame.rtp_timestamp(), webrtc::kVideoCodecClockrate);
    380  return VideoData::CreateFromImage(image->GetSize(), 0, timestamp, aDuration,
    381                                    image, aIsKeyFrame, timestamp);
    382 }
    383 
    384 static void UpdateCodecSpecificInfo(webrtc::CodecSpecificInfo& aInfo,
    385                                    const gfx::IntSize& aSize,
    386                                    const bool aIsKeyframe) {
    387  switch (aInfo.codecType) {
    388    case webrtc::VideoCodecType::kVideoCodecVP8: {
    389      // See webrtc::VP8EncoderImpl::PopulateCodecSpecific().
    390      webrtc::CodecSpecificInfoVP8& vp8 = aInfo.codecSpecific.VP8;
    391      vp8.keyIdx = webrtc::kNoKeyIdx;
    392      // Cannot be 100% sure unless parsing significant portion of the
    393      // bitstream. Treat all frames as referenced just to be safe.
    394      vp8.nonReference = false;
    395      // One temporal layer only.
    396      vp8.temporalIdx = webrtc::kNoTemporalIdx;
    397      vp8.layerSync = false;
    398      break;
    399    }
    400    case webrtc::VideoCodecType::kVideoCodecVP9: {
    401      // See webrtc::VP9EncoderImpl::PopulateCodecSpecific().
    402      webrtc::CodecSpecificInfoVP9& vp9 = aInfo.codecSpecific.VP9;
    403      vp9.inter_pic_predicted = !aIsKeyframe;
    404      vp9.ss_data_available = aIsKeyframe && !vp9.flexible_mode;
    405      // One temporal & spatial layer only.
    406      vp9.temporal_idx = webrtc::kNoTemporalIdx;
    407      vp9.temporal_up_switch = false;
    408      vp9.num_spatial_layers = 1;
    409      aInfo.end_of_picture = true;
    410      vp9.gof_idx = webrtc::kNoGofIdx;
    411      vp9.width[0] = aSize.width;
    412      vp9.height[0] = aSize.height;
    413      break;
    414    }
    415    default:
    416      break;
    417  }
    418 }
    419 
    420 static void GetVPXQp(const webrtc::VideoCodecType aType,
    421                     webrtc::EncodedImage& aImage) {
    422  switch (aType) {
    423    case webrtc::VideoCodecType::kVideoCodecVP8:
    424      webrtc::vp8::GetQp(aImage.data(), aImage.size(), &(aImage.qp_));
    425      break;
    426    case webrtc::VideoCodecType::kVideoCodecVP9:
    427      webrtc::vp9::GetQp(aImage.data(), aImage.size(), &(aImage.qp_));
    428      break;
    429    default:
    430      break;
    431  }
    432 }
    433 
    434 int32_t WebrtcMediaDataEncoder::Encode(
    435    const webrtc::VideoFrame& aInputFrame,
    436    const std::vector<webrtc::VideoFrameType>* aFrameTypes) {
    437  if (!aInputFrame.size() || !aInputFrame.video_frame_buffer() ||
    438      aFrameTypes->empty()) {
    439    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    440  }
    441 
    442  if (!mEncoder) {
    443    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    444  }
    445  {
    446    MutexAutoLock lock(mCallbackMutex);
    447    if (!mCallback) {
    448      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    449    }
    450    if (NS_FAILED(mError)) {
    451      return WEBRTC_VIDEO_CODEC_ERROR;
    452    }
    453  }
    454 
    455  LOG_V("Encode frame, type %d size %u", static_cast<int>((*aFrameTypes)[0]),
    456        aInputFrame.size());
    457  MOZ_ASSERT(aInputFrame.video_frame_buffer()->type() ==
    458             webrtc::VideoFrameBuffer::Type::kI420);
    459  RefPtr<VideoData> data = CreateVideoDataFromWebrtcVideoFrame(
    460      aInputFrame, (*aFrameTypes)[0] == webrtc::VideoFrameType::kVideoFrameKey,
    461      TimeUnit::FromSeconds(1.0 / mMaxFrameRate));
    462  const gfx::IntSize displaySize = data->mDisplay;
    463 
    464  mEncoder->Encode(data)->Then(
    465      mTaskQueue, __func__,
    466      [self = RefPtr<WebrtcMediaDataEncoder>(this), this,
    467       displaySize](MediaDataEncoder::EncodedData aFrames) {
    468        LOG_V("Received encoded frame, nums %zu width %d height %d",
    469              aFrames.Length(), displaySize.width, displaySize.height);
    470        for (auto& frame : aFrames) {
    471          MutexAutoLock lock(mCallbackMutex);
    472          if (!mCallback) {
    473            break;
    474          }
    475          webrtc::EncodedImage image;
    476          image.SetEncodedData(
    477              webrtc::EncodedImageBuffer::Create(frame->Data(), frame->Size()));
    478          image._encodedWidth = displaySize.width;
    479          image._encodedHeight = displaySize.height;
    480          CheckedInt64 time =
    481              TimeUnitToFrames(frame->mTime, webrtc::kVideoCodecClockrate);
    482          if (!time.isValid()) {
    483            self->mError = MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    484                                       "invalid timestamp from encoder");
    485            break;
    486          }
    487          image.SetRtpTimestamp(time.value());
    488          image._frameType = frame->mKeyframe
    489                                 ? webrtc::VideoFrameType::kVideoFrameKey
    490                                 : webrtc::VideoFrameType::kVideoFrameDelta;
    491          GetVPXQp(mCodecSpecific.codecType, image);
    492          UpdateCodecSpecificInfo(mCodecSpecific, displaySize,
    493                                  frame->mKeyframe);
    494 
    495          LOG_V("Send encoded image");
    496          self->mCallback->OnEncodedImage(image, &mCodecSpecific);
    497          self->mBitrateAdjuster.Update(image.size());
    498        }
    499      },
    500      [self = RefPtr<WebrtcMediaDataEncoder>(this)](const MediaResult& aError) {
    501        self->mError = aError;
    502      });
    503  return WEBRTC_VIDEO_CODEC_OK;
    504 }
    505 
    506 int32_t WebrtcMediaDataEncoder::SetRates(
    507    const webrtc::VideoEncoder::RateControlParameters& aParameters) {
    508  if (!aParameters.bitrate.HasBitrate(0, 0)) {
    509    LOG("%s: no bitrate value to set.", __func__);
    510    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    511  }
    512  MOZ_ASSERT(aParameters.bitrate.IsSpatialLayerUsed(0));
    513  MOZ_ASSERT(!aParameters.bitrate.IsSpatialLayerUsed(1),
    514             "No simulcast support for platform encoder");
    515 
    516  const uint32_t newBitrateBps = aParameters.bitrate.GetBitrate(0, 0);
    517  if (newBitrateBps < mMinBitrateBps || newBitrateBps > mMaxBitrateBps) {
    518    LOG("%s: bitrate value out of range.", __func__);
    519    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    520  }
    521 
    522  // We have already been in this bitrate.
    523  if (mBitrateAdjuster.GetAdjustedBitrateBps() == newBitrateBps) {
    524    return WEBRTC_VIDEO_CODEC_OK;
    525  }
    526 
    527  if (!mEncoder) {
    528    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    529  }
    530  {
    531    MutexAutoLock lock(mCallbackMutex);
    532    if (NS_FAILED(mError)) {
    533      return WEBRTC_VIDEO_CODEC_ERROR;
    534    }
    535  }
    536  mBitrateAdjuster.SetTargetBitrateBps(newBitrateBps);
    537  LOG("Set bitrate %u bps, minBitrate %u bps, maxBitrate %u bps", newBitrateBps,
    538      mMinBitrateBps, mMaxBitrateBps);
    539  auto rv =
    540      media::Await(do_AddRef(mTaskQueue), mEncoder->SetBitrate(newBitrateBps));
    541  return rv.IsResolve() ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR;
    542 }
    543 
    544 }  // namespace mozilla