mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
5983fc106d
Differential Revision: https://phabricator.services.mozilla.com/D213987
210 lines
7.2 KiB
C++
210 lines
7.2 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "PlatformEncoderModule.h"
|
|
#include "H264.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "mozilla/ToString.h"
|
|
|
|
namespace mozilla {
|
|
|
|
extern LazyLogModule sPEMLog;
|
|
#define LOGD(fmt, ...) \
|
|
MOZ_LOG(sPEMLog, mozilla::LogLevel::Debug, \
|
|
("PEM: %s: " fmt, __func__, ##__VA_ARGS__))
|
|
|
|
// TODO: Automatically generate this (Bug 1865896)
|
|
const char* GetCodecTypeString(const CodecType& aCodecType) {
|
|
switch (aCodecType) {
|
|
case CodecType::_BeginVideo_:
|
|
return "_BeginVideo_";
|
|
case CodecType::H264:
|
|
return "H264";
|
|
case CodecType::VP8:
|
|
return "VP8";
|
|
case CodecType::VP9:
|
|
return "VP9";
|
|
case CodecType::AV1:
|
|
return "AV1";
|
|
case CodecType::_EndVideo_: // CodecType::_BeginAudio_
|
|
return "_EndVideo_/_BeginAudio_";
|
|
case CodecType::Opus:
|
|
return "Opus";
|
|
case CodecType::Vorbis:
|
|
return "Vorbis";
|
|
case CodecType::Flac:
|
|
return "Flac";
|
|
case CodecType::AAC:
|
|
return "AAC";
|
|
case CodecType::PCM:
|
|
return "PCM";
|
|
break;
|
|
case CodecType::G722:
|
|
return "G722";
|
|
case CodecType::_EndAudio_:
|
|
return "_EndAudio_";
|
|
case CodecType::Unknown:
|
|
return "Unknown";
|
|
}
|
|
MOZ_ASSERT_UNREACHABLE("undefined codec type");
|
|
return "Undefined";
|
|
}
|
|
|
|
RefPtr<PlatformEncoderModule::CreateEncoderPromise>
|
|
PlatformEncoderModule::AsyncCreateEncoder(const EncoderConfig& aEncoderConfig,
|
|
const RefPtr<TaskQueue>& aTaskQueue) {
|
|
RefPtr<MediaDataEncoder> encoder;
|
|
MediaResult result = NS_OK;
|
|
if (aEncoderConfig.IsAudio()) {
|
|
encoder = CreateAudioEncoder(aEncoderConfig, aTaskQueue);
|
|
} else if (aEncoderConfig.IsVideo()) {
|
|
encoder = CreateVideoEncoder(aEncoderConfig, aTaskQueue);
|
|
}
|
|
if (!encoder) {
|
|
if (NS_FAILED(result)) {
|
|
return CreateEncoderPromise::CreateAndReject(result, __func__);
|
|
}
|
|
return CreateEncoderPromise::CreateAndReject(
|
|
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
|
nsPrintfCString("Error creating encoder for %d",
|
|
static_cast<int>(aEncoderConfig.mCodec))
|
|
.get()),
|
|
__func__);
|
|
}
|
|
return CreateEncoderPromise::CreateAndResolve(encoder, __func__);
|
|
}
|
|
|
|
template <typename T>
|
|
nsCString MaybeToString(const Maybe<T>& aMaybe) {
|
|
return nsPrintfCString(
|
|
"%s", aMaybe.isSome() ? ToString(aMaybe.value()).c_str() : "nothing");
|
|
}
|
|
|
|
struct ConfigurationChangeToString {
|
|
nsCString operator()(const DimensionsChange& aDimensionsChange) {
|
|
return nsPrintfCString("Dimensions: %dx%d", aDimensionsChange.get().width,
|
|
aDimensionsChange.get().height);
|
|
}
|
|
nsCString operator()(const DisplayDimensionsChange& aDisplayDimensionChange) {
|
|
if (aDisplayDimensionChange.get().isNothing()) {
|
|
return nsCString("Display dimensions: nothing");
|
|
}
|
|
gfx::IntSize displayDimensions = aDisplayDimensionChange.get().value();
|
|
return nsPrintfCString("Display dimensions: %dx%d", displayDimensions.width,
|
|
displayDimensions.height);
|
|
}
|
|
nsCString operator()(const BitrateChange& aBitrateChange) {
|
|
if (aBitrateChange.get().isSome()) {
|
|
return nsLiteralCString("Bitrate: nothing");
|
|
}
|
|
return nsPrintfCString("Bitrate: %skbps",
|
|
MaybeToString(aBitrateChange.get()).get());
|
|
}
|
|
nsCString operator()(const FramerateChange& aFramerateChange) {
|
|
if (aFramerateChange.get().isNothing()) {
|
|
return nsCString("Framerate: nothing");
|
|
}
|
|
return nsPrintfCString("Framerate: %lfHz", aFramerateChange.get().value());
|
|
}
|
|
nsCString operator()(const BitrateModeChange& aBitrateModeChange) {
|
|
return nsPrintfCString("Bitrate mode: %s",
|
|
aBitrateModeChange.get() == BitrateMode::Constant
|
|
? "Constant"
|
|
: "Variable");
|
|
}
|
|
nsCString operator()(const UsageChange& aUsageChange) {
|
|
return nsPrintfCString(
|
|
"Usage mode: %s",
|
|
aUsageChange.get() == Usage::Realtime ? "Realtime" : "Recoding");
|
|
}
|
|
nsCString operator()(const ContentHintChange& aContentHintChange) {
|
|
return nsPrintfCString("Content hint: %s",
|
|
MaybeToString(aContentHintChange.get()).get());
|
|
}
|
|
nsCString operator()(const SampleRateChange& aSampleRateChange) {
|
|
return nsPrintfCString("Sample rate %" PRIu32 "Hz",
|
|
aSampleRateChange.get());
|
|
}
|
|
nsCString operator()(const NumberOfChannelsChange& aNumberOfChannelsChange) {
|
|
return nsPrintfCString("Channels: %" PRIu32 "Hz",
|
|
aNumberOfChannelsChange.get());
|
|
}
|
|
};
|
|
|
|
nsString EncoderConfigurationChangeList::ToString() const {
|
|
nsString rv(
|
|
NS_LITERAL_STRING_FROM_CSTRING("EncoderConfigurationChangeList:"_ns));
|
|
for (const EncoderConfigurationItem& change : mChanges) {
|
|
nsCString str = change.match(ConfigurationChangeToString());
|
|
rv.AppendPrintf("- %s\n", str.get());
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
bool CanLikelyEncode(const EncoderConfig& aConfig) {
|
|
if (aConfig.mCodec == CodecType::H264) {
|
|
if (!aConfig.mCodecSpecific ||
|
|
!aConfig.mCodecSpecific->is<H264Specific>()) {
|
|
LOGD(
|
|
"Error: asking for support codec for h264 without h264 specific "
|
|
"config.");
|
|
return false;
|
|
}
|
|
H264Specific specific = aConfig.mCodecSpecific->as<H264Specific>();
|
|
int width = aConfig.mSize.width;
|
|
int height = aConfig.mSize.height;
|
|
if (width % 2 || !width) {
|
|
LOGD("Invalid width of %d for h264", width);
|
|
return false;
|
|
}
|
|
if (height % 2 || !height) {
|
|
LOGD("Invalid height of %d for h264", height);
|
|
return false;
|
|
}
|
|
if (specific.mProfile != H264_PROFILE_BASE &&
|
|
specific.mProfile != H264_PROFILE_MAIN &&
|
|
specific.mProfile != H264_PROFILE_HIGH) {
|
|
LOGD("Invalid profile of %x for h264", specific.mProfile);
|
|
return false;
|
|
}
|
|
// x264 (Linux software) and some Windows configuration (e.g. some nvidia
|
|
// hardware) support level 62 which supports 8k
|
|
if ((specific.mLevel >= H264_LEVEL::H264_LEVEL_6) &&
|
|
(width > 2 * 4096 || height > 2 * 4096)) {
|
|
LOGD("Invalid size of %dx%d for h264", width, height);
|
|
return false;
|
|
}
|
|
// Levels strictly below 6 are limited to 4096x4096px
|
|
if (specific.mLevel < H264_LEVEL::H264_LEVEL_6 &&
|
|
(width > 4096 || height > 4096)) {
|
|
LOGD("Invalid size of %dx%d for h264", width, height);
|
|
return false;
|
|
}
|
|
}
|
|
if (aConfig.mCodec == CodecType::VP8) {
|
|
int width = aConfig.mSize.width;
|
|
int height = aConfig.mSize.height;
|
|
if (width > 2 << 13 || height > 2 << 13) {
|
|
LOGD("Invalid size of %dx%d for VP8", width, height);
|
|
return false;
|
|
}
|
|
}
|
|
if (aConfig.mCodec == CodecType::VP9) {
|
|
int width = aConfig.mSize.width;
|
|
int height = aConfig.mSize.height;
|
|
if (width > 2 << 15 || height > 2 << 15) {
|
|
LOGD("Invalid size of %dx%d for VP9", width, height);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace mozilla
|
|
|
|
#undef LOGD
|