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