blob: 72a93b8a767cc93eb29bef1735a40da3c5ac2100 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/video_encoder.h"
#include <algorithm>
#include "base/numerics/checked_math.h"
#include "base/numerics/clamped_math.h"
#include "base/strings/stringprintf.h"
#include "base/strings/to_string.h"
#include "base/system/sys_info.h"
#include "media/base/media_switches.h"
#include "media/base/video_frame.h"
namespace media {
namespace {
const char* GetContentHintName(VideoEncoder::ContentHint content_hint) {
switch (content_hint) {
case VideoEncoder::ContentHint::Camera:
return "camera";
case VideoEncoder::ContentHint::Screen:
return "screen";
}
}
} // namespace
uint8_t GetDefaultVideoEncoderDropFrameThreshold() {
// This function is to be invoked only in WebCodecs usage.
// The drop frame threshold is the same as WebRTC.
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc
return base::FeatureList::IsEnabled(kWebCodecsVideoEncoderFrameDrop) ? 30 : 0;
}
uint32_t GetDefaultVideoEncodeBitrate(gfx::Size frame_size,
uint32_t framerate) {
// Let's default to 2M bps for HD at 30 fps.
const uint32_t kDefaultBitrateForHD30fps = 2'000'000u;
const uint32_t kHDArea = 1280u * 720u;
const int kMaxArea = 8000 * 8000;
const uint64_t kMinBitrate = 10000;
const uint64_t kMaxBitrate = std::numeric_limits<uint32_t>::max();
// Scale default bitrate to the given frame size and fps
base::ClampedNumeric<uint64_t> result = kDefaultBitrateForHD30fps;
result *= std::clamp(framerate, 1u, 300u);
result *= std::clamp(frame_size.GetArea(), 1, kMaxArea);
result /= kHDArea * 30u; // HD resolution, 30 fps
return std::clamp(result.RawValue(), kMinBitrate, kMaxBitrate);
}
int GetNumberOfThreadsForSoftwareEncoding(gfx::Size frame_size) {
int area = frame_size.GetCheckedArea().ValueOrDefault(1);
// Default to 1 thread for less than VGA.
int desired_threads = 1;
if (area >= 3840 * 2160) {
desired_threads = 16;
} else if (area >= 1920 * 1080) {
desired_threads = 8;
} else if (area >= 1280 * 720) {
desired_threads = 4;
} else if (area >= 640 * 480) {
desired_threads = 2;
}
// Clamp to the number of available logical processors/cores.
desired_threads =
std::min(desired_threads, base::SysInfo::NumberOfProcessors());
return desired_threads;
}
VideoEncoderOutput::VideoEncoderOutput() = default;
VideoEncoderOutput::VideoEncoderOutput(VideoEncoderOutput&&) = default;
VideoEncoderOutput::~VideoEncoderOutput() = default;
VideoEncoder::VideoEncoder() = default;
VideoEncoder::~VideoEncoder() = default;
VideoEncoder::Options::Options() = default;
VideoEncoder::Options::Options(const Options&) = default;
VideoEncoder::Options::~Options() = default;
std::string VideoEncoder::Options::ToString() {
std::vector<std::string> keys;
if (bitrate) {
keys.push_back("bitrate: " + bitrate->ToString());
}
if (framerate) {
keys.push_back(base::StringPrintf("framerate: %f", *framerate));
}
keys.push_back("frame_size: " + frame_size.ToString());
if (keyframe_interval) {
keys.push_back(
base::StringPrintf("keyframe_interval: %d", *keyframe_interval));
}
keys.push_back(base::StringPrintf(
"latency_mode: %s",
latency_mode == LatencyMode::Quality ? "quality" : "realtime"));
if (scalability_mode) {
keys.push_back(base::StringPrintf(
"scalability_mode: %s", GetScalabilityModeName(*scalability_mode)));
}
if (content_hint) {
keys.push_back(base::StringPrintf("content_hint: %s",
GetContentHintName(*content_hint)));
}
if (subsampling) {
keys.push_back("subsampling: " + VideoChromaSamplingToString(*subsampling));
}
if (bit_depth) {
keys.push_back(base::StringPrintf("bit_depth: %d", *bit_depth));
}
keys.push_back(base::StringPrintf(
"produce_annexb: %s",
base::ToString(avc.produce_annexb || hevc.produce_annexb)));
return base::JoinString(keys, ", ");
}
VideoEncoder::PendingEncode::PendingEncode() = default;
VideoEncoder::PendingEncode::PendingEncode(PendingEncode&&) = default;
VideoEncoder::PendingEncode::~PendingEncode() = default;
VideoEncoder::EncodeOptions::EncodeOptions(bool key_frame)
: key_frame(key_frame) {}
VideoEncoder::EncodeOptions::EncodeOptions() = default;
VideoEncoder::EncodeOptions::EncodeOptions(const EncodeOptions&) = default;
VideoEncoder::EncodeOptions::~EncodeOptions() = default;
void VideoEncoder::DisablePostedCallbacks() {
post_callbacks_ = false;
}
} // namespace media