Skip to content

Commit

Permalink
Add Support for Codec Information in PlatformInfoSerializer
Browse files Browse the repository at this point in the history
This CL adds support for Codec information in the
PlatformInfoSerializer.
This is required so that the Cast Web Runtime may start the Openscreen
Streaming Receiver, as seen here:
https://source.chromium.org/chromium/chromium/src/+/main:components/cast_streaming/browser/public/receiver_session.h;l=31

Internally, this will be populated using the MediaCapabilitiesShlib
functions:
https://source.chromium.org/chromium/chromium/src/+/main:chromecast/public/media/media_capabilities_shlib.h

Bug: b/182427395
Change-Id: Ia1f78abed9f35346a65959fb50eda00448833776
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2988152
Reviewed-by: Jiawei Li <lijiawei@chromium.org>
Reviewed-by: Yuchen Liu <yucliu@chromium.org>
Commit-Queue: Ryan Keane <rwkeane@google.com>
Cr-Commit-Position: refs/heads/master@{#896793}
  • Loading branch information
Ryan Keane authored and Chromium LUCI CQ committed Jun 29, 2021
1 parent 39a24ca commit 7de5567
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 13 deletions.
5 changes: 4 additions & 1 deletion chromecast/shared/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ cast_source_set("platform_info_serializer") {
"platform_info_serializer.h",
]

public_deps = [ "//base" ]
public_deps = [
"//base",
"//chromecast/public/media",
]
}

test("cast_shared_unittests") {
Expand Down
3 changes: 3 additions & 0 deletions chromecast/shared/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+chromecast/public/media",
]
208 changes: 200 additions & 8 deletions chromecast/shared/platform_info_serializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,44 +47,170 @@ constexpr char kSpatialRenderingSupportMaskProperty[] =
"spatialRenderingSupportMask";
constexpr char kMaxFillrateProperty[] = "maxFillrate";

// Audio Codec information
constexpr char kSupportedAudioCodecsProperty[] = "supportedAudioCodecs";
constexpr char kAudioCodecInfoCodecKey[] = "codec";
constexpr char kAudioCodecInfoSampleFormat[] = "sampleFormat";
constexpr char kAudioCodecInfoSamplesPerSecond[] = "samplesPerSecond";
constexpr char kAudioCodecInfoMaxAudioChannelsKey[] = "maxAudioChannels";

// Video Codec information
constexpr char kSupportedVideoCodecsProperty[] = "supportedVideoCodecs";
constexpr char kVideoCodecInfoCodecKey[] = "codec";
constexpr char kVideoCodecInfoProfileKey[] = "profile";

// Attempts to parse |value| as the given type, returning absl::nullopt on
// failure.
template <typename T>
absl::optional<T> Parse(const base::Value& value);
struct Parser {
static absl::optional<T> Parse(const base::Value& value);
};

template <typename T>
struct Parser<std::vector<T>> {
static absl::optional<std::vector<T>> Parse(const base::Value& value);
};

// Tries to populate values of the given type |T| from |value| into
// |destination|, returning whether the operation succeeded.
template <typename T>
bool TryPopulateValue(const base::Value* value, T* destination) {
DCHECK(destination);

if (!value) {
return false;
}

auto parsed = Parser<T>::Parse(*value);
if (!parsed.has_value()) {
return false;
}

*destination = std::move(parsed.value());
return true;
}

// Parses an enum value. To be used as a helper when implementing the above.
template <typename T>
absl::optional<T> ParseEnum(const base::Value& value) {
absl::optional<int> parsed_int = Parser<int>::Parse(value);
if (!parsed_int.has_value()) {
return absl::nullopt;
}
return static_cast<T>(parsed_int.value());
}

template <>
inline absl::optional<media::AudioCodec> Parser<media::AudioCodec>::Parse(
const base::Value& value) {
return ParseEnum<media::AudioCodec>(value);
}

template <>
inline absl::optional<media::SampleFormat> Parser<media::SampleFormat>::Parse(
const base::Value& value) {
return ParseEnum<media::SampleFormat>(value);
}

template <>
inline absl::optional<media::VideoCodec> Parser<media::VideoCodec>::Parse(
const base::Value& value) {
return ParseEnum<media::VideoCodec>(value);
}

template <>
inline absl::optional<media::VideoProfile> Parser<media::VideoProfile>::Parse(
const base::Value& value) {
return ParseEnum<media::VideoProfile>(value);
}

template <>
absl::optional<bool> Parse<bool>(const base::Value& value) {
absl::optional<bool> Parser<bool>::Parse(const base::Value& value) {
if (!value.is_bool()) {
return absl::nullopt;
}
return value.GetBool();
}

template <>
absl::optional<int> Parse<int>(const base::Value& value) {
absl::optional<int> Parser<int>::Parse(const base::Value& value) {
if (!value.is_int()) {
return absl::nullopt;
}
return value.GetInt();
}

template <>
absl::optional<std::string> Parse<std::string>(const base::Value& value) {
absl::optional<std::string> Parser<std::string>::Parse(
const base::Value& value) {
if (!value.is_string()) {
return absl::nullopt;
}
return value.GetString();
}

template <>
absl::optional<std::vector<int>> Parse<std::vector<int>>(
absl::optional<PlatformInfoSerializer::AudioCodecInfo>
Parser<PlatformInfoSerializer::AudioCodecInfo>::Parse(
const base::Value& value) {
if (!value.is_dict()) {
return absl::nullopt;
}

const base::Value* codec_value = value.FindKey(kAudioCodecInfoCodecKey);
const base::Value* sample_format_value =
value.FindKey(kAudioCodecInfoSampleFormat);
const base::Value* samples_per_second_value =
value.FindKey(kAudioCodecInfoSamplesPerSecond);
const base::Value* max_audio_channels_value =
value.FindKey(kAudioCodecInfoMaxAudioChannelsKey);

PlatformInfoSerializer::AudioCodecInfo audio_codec_info;
if (!TryPopulateValue(codec_value, &audio_codec_info.codec)) {
return absl::nullopt;
}

TryPopulateValue(sample_format_value, &audio_codec_info.sample_format);
TryPopulateValue(samples_per_second_value,
&audio_codec_info.max_samples_per_second);
TryPopulateValue(max_audio_channels_value,
&audio_codec_info.max_audio_channels);

return audio_codec_info;
}

template <>
absl::optional<PlatformInfoSerializer::VideoCodecInfo>
Parser<PlatformInfoSerializer::VideoCodecInfo>::Parse(
const base::Value& value) {
if (!value.is_dict()) {
return absl::nullopt;
}

const base::Value* codec_value = value.FindKey(kVideoCodecInfoCodecKey);
const base::Value* profiles_value = value.FindKey(kVideoCodecInfoProfileKey);

PlatformInfoSerializer::VideoCodecInfo video_codec_info;
if (!TryPopulateValue(codec_value, &video_codec_info.codec)) {
return absl::nullopt;
}

TryPopulateValue(profiles_value, &video_codec_info.profile);

return video_codec_info;
}

template <typename T>
absl::optional<std::vector<T>> Parser<std::vector<T>>::Parse(
const base::Value& value) {
if (!value.is_list()) {
return absl::nullopt;
}
base::Value::ConstListView list = value.GetList();
std::vector<int> results;
std::vector<T> results;
results.reserve(list.size());
for (const auto& element : list) {
auto parsed_element = Parse<int>(element);
auto parsed_element = Parser<T>::Parse(element);
if (!parsed_element.has_value()) {
return absl::nullopt;
}
Expand All @@ -101,7 +227,38 @@ absl::optional<T> ParseWithKey(const base::DictionaryValue& dictionary,
return absl::nullopt;
}

return Parse<T>(*value);
return Parser<T>::Parse(*value);
}

void SetWithKey(base::DictionaryValue* dictionary,
std::vector<PlatformInfoSerializer::AudioCodecInfo> elements) {
DCHECK(dictionary);
base::ListValue list;
for (const auto& element : elements) {
base::DictionaryValue audio_codec_value;
audio_codec_value.SetIntKey(kAudioCodecInfoCodecKey, element.codec);
audio_codec_value.SetIntKey(kAudioCodecInfoSampleFormat,
element.sample_format);
audio_codec_value.SetIntKey(kAudioCodecInfoSamplesPerSecond,
element.max_samples_per_second);
audio_codec_value.SetIntKey(kAudioCodecInfoMaxAudioChannelsKey,
element.max_audio_channels);
list.Append(std::move(audio_codec_value));
}
dictionary->SetKey(kSupportedAudioCodecsProperty, std::move(list));
}

void SetWithKey(base::DictionaryValue* dictionary,
std::vector<PlatformInfoSerializer::VideoCodecInfo> elements) {
DCHECK(dictionary);
base::ListValue list;
for (auto& element : elements) {
base::DictionaryValue video_codec_value;
video_codec_value.SetIntKey(kVideoCodecInfoCodecKey, element.codec);
video_codec_value.SetIntKey(kVideoCodecInfoProfileKey, element.profile);
list.Append(std::move(video_codec_value));
}
dictionary->SetKey(kSupportedVideoCodecsProperty, std::move(list));
}

} // namespace
Expand Down Expand Up @@ -240,6 +397,16 @@ void PlatformInfoSerializer::SetMaxFillRate(int max_fill_rate) {
platform_info_.SetIntKey(kMaxFillrateProperty, max_fill_rate);
}

void PlatformInfoSerializer::SetSupportedAudioCodecs(
std::vector<AudioCodecInfo> codec_infos) {
SetWithKey(&platform_info_, std::move(codec_infos));
}

void PlatformInfoSerializer::SetSupportedVideoCodecs(
std::vector<VideoCodecInfo> codec_infos) {
SetWithKey(&platform_info_, std::move(codec_infos));
}

absl::optional<int> PlatformInfoSerializer::MaxWidth() const {
return ParseWithKey<int>(platform_info_, kMaxWidthProperty);
}
Expand Down Expand Up @@ -342,11 +509,36 @@ absl::optional<int> PlatformInfoSerializer::MaxFillRate() const {
return ParseWithKey<int>(platform_info_, kMaxFillrateProperty);
}

absl::optional<std::vector<PlatformInfoSerializer::AudioCodecInfo>>
PlatformInfoSerializer::SupportedAudioCodecs() const {
return ParseWithKey<std::vector<AudioCodecInfo>>(
platform_info_, kSupportedAudioCodecsProperty);
}

absl::optional<std::vector<PlatformInfoSerializer::VideoCodecInfo>>
PlatformInfoSerializer::SupportedVideoCodecs() const {
return ParseWithKey<std::vector<VideoCodecInfo>>(
platform_info_, kSupportedVideoCodecsProperty);
}

std::string PlatformInfoSerializer::ToJson() const {
std::string json;
bool success = base::JSONWriter::Write(platform_info_, &json);
DCHECK(success);
return json;
}

bool operator==(const PlatformInfoSerializer::AudioCodecInfo& first,
const PlatformInfoSerializer::AudioCodecInfo& second) {
return first.codec == second.codec &&
first.sample_format == second.sample_format &&
first.max_samples_per_second == second.max_samples_per_second &&
first.max_audio_channels == second.max_audio_channels;
}

bool operator==(const PlatformInfoSerializer::VideoCodecInfo& first,
const PlatformInfoSerializer::VideoCodecInfo& second) {
return first.codec == second.codec && first.profile == second.profile;
}

} // namespace chromecast
36 changes: 32 additions & 4 deletions chromecast/shared/platform_info_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <vector>

#include "base/values.h"
#include "chromecast/public/media/decoder_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace chromecast {
Expand All @@ -17,6 +18,21 @@ namespace chromecast {
// messages used for specifying the media capabilities of a Cast receiver.
class PlatformInfoSerializer {
public:
// Information about a supported audio codec.
struct AudioCodecInfo {
media::AudioCodec codec = media::AudioCodec::kAudioCodecUnknown;
media::SampleFormat sample_format =
media::SampleFormat::kUnknownSampleFormat;
int max_samples_per_second = 0;
int max_audio_channels = 0;
};

// Information about a supported video codec.
struct VideoCodecInfo {
media::VideoCodec codec = media::VideoCodec::kVideoCodecUnknown;
media::VideoProfile profile = media::VideoProfile::kVideoProfileUnknown;
};

PlatformInfoSerializer();
PlatformInfoSerializer(PlatformInfoSerializer&& other);

Expand All @@ -26,14 +42,14 @@ class PlatformInfoSerializer {
bool operator==(const PlatformInfoSerializer& other) const;
bool operator!=(const PlatformInfoSerializer& other) const;

// Tries to parse the provided json, returning base::nullopt on failure.
// Tries to parse the provided json, returning absl::nullopt on failure.
static absl::optional<PlatformInfoSerializer> TryParse(
base::StringPiece json);

// Serializes |platform_info_| into json.
std::string ToJson() const;

// Setters for known properties.
// Setters for known valid properties.
void SetMaxWidth(int max_width);
void SetMaxHeight(int max_height);
void SetMaxFrameRate(int max_frame_rate);
Expand All @@ -51,10 +67,11 @@ class PlatformInfoSerializer {
void SetSmpteSt2084Supported(bool is_supported);
void SetHglSupported(bool is_supported);
void SetHdrFeatureEnabled(bool is_enabled);
void SetSupportedLegacyVp9Levels(std::vector<int> levels);
void SetHdcpVersion(int hdcp_version);
void SetSpatialRenderingSupportMask(int mask);
void SetMaxFillRate(int max_fill_rate);
void SetSupportedAudioCodecs(std::vector<AudioCodecInfo> codec_infos);
void SetSupportedVideoCodecs(std::vector<VideoCodecInfo> codec_infos);

// Getters for the same properties. Returns absl::nullopt if no such value is
// set, and the set value in all other cases.
Expand All @@ -75,16 +92,27 @@ class PlatformInfoSerializer {
absl::optional<bool> IsSmpteSt2084Supported() const;
absl::optional<bool> IsHglSupported() const;
absl::optional<bool> IsHdrFeatureEnabled() const;
absl::optional<std::vector<int>> SupportedLegacyVp9Levels() const;
absl::optional<int> HdcpVersion() const;
absl::optional<int> SpatialRenderingSupportMask() const;
absl::optional<int> MaxFillRate() const;
absl::optional<std::vector<AudioCodecInfo>> SupportedAudioCodecs() const;
absl::optional<std::vector<VideoCodecInfo>> SupportedVideoCodecs() const;

// Deprecated fields.
void SetSupportedLegacyVp9Levels(std::vector<int> levels);
absl::optional<std::vector<int>> SupportedLegacyVp9Levels() const;

private:
// All currently produced values.
base::DictionaryValue platform_info_;
};

bool operator==(const PlatformInfoSerializer::AudioCodecInfo& first,
const PlatformInfoSerializer::AudioCodecInfo& second);

bool operator==(const PlatformInfoSerializer::VideoCodecInfo& first,
const PlatformInfoSerializer::VideoCodecInfo& second);

} // namespace chromecast

#endif // CHROMECAST_SHARED_PLATFORM_INFO_SERIALIZER_H_
Loading

0 comments on commit 7de5567

Please sign in to comment.