diff options
author | eero.hakkinen <eero.hakkinen@intel.com> | 2016-03-21 00:59:48 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-21 08:00:59 +0000 |
commit | 2c13e7ad077ec639b6ca0e76f0a1a530a398cb9d (patch) | |
tree | 8bbd8898a1f4217224eeb2bab72a8e8d6fbb5ed4 /extensions/renderer | |
parent | 6af7ef0418bea43e80ff4cd05ea70d7f12d369b2 (diff) | |
download | chromium_src-2c13e7ad077ec639b6ca0e76f0a1a530a398cb9d.zip chromium_src-2c13e7ad077ec639b6ca0e76f0a1a530a398cb9d.tar.gz chromium_src-2c13e7ad077ec639b6ca0e76f0a1a530a398cb9d.tar.bz2 |
[chrome.displaySource] Implement some elementary stream descriptors.
WiFi Display elementary stream descriptors are used for passing descriptive
information about elementary streams to a WiFi Display transport stream
packetizer which then packetizes that information so that it can be passed
to a remote sink.
This is part of a WiFi Display packetizer patch series:
* https://codereview.chromium.org/1796123002/
WiFi Display elementary stream packetizer
* https://codereview.chromium.org/1800493003/ <-- this CL
WiFi Display elementary stream descriptors
* https://codereview.chromium.org/1797953002/
WiFi Display transport stream packetizer
* https://codereview.chromium.org/1796073003/
WiFi Display media packetizer
BUG=242107
Review URL: https://codereview.chromium.org/1800493003
Cr-Commit-Position: refs/heads/master@{#382245}
Diffstat (limited to 'extensions/renderer')
3 files changed, 438 insertions, 0 deletions
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.cc new file mode 100644 index 0000000..7f59ce6 --- /dev/null +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.cc @@ -0,0 +1,165 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h" + +#include <cstring> + +namespace extensions { + +WiFiDisplayElementaryStreamDescriptor::WiFiDisplayElementaryStreamDescriptor( + const WiFiDisplayElementaryStreamDescriptor& other) { + if (!other.empty()) { + data_.reset(new uint8_t[other.size()]); + std::memcpy(data(), other.data(), other.size()); + } +} + +WiFiDisplayElementaryStreamDescriptor::WiFiDisplayElementaryStreamDescriptor( + WiFiDisplayElementaryStreamDescriptor&&) = default; + +WiFiDisplayElementaryStreamDescriptor::WiFiDisplayElementaryStreamDescriptor( + DescriptorTag tag, + uint8_t length) + : data_(new uint8_t[kHeaderSize + length]) { + uint8_t* p = data(); + *p++ = tag; + *p++ = length; + DCHECK_EQ(private_data(), p); +} + +WiFiDisplayElementaryStreamDescriptor:: + ~WiFiDisplayElementaryStreamDescriptor() {} + +WiFiDisplayElementaryStreamDescriptor& WiFiDisplayElementaryStreamDescriptor:: +operator=(WiFiDisplayElementaryStreamDescriptor&&) = default; + +const uint8_t* WiFiDisplayElementaryStreamDescriptor::data() const { + return data_.get(); +} + +uint8_t* WiFiDisplayElementaryStreamDescriptor::data() { + return data_.get(); +} + +size_t WiFiDisplayElementaryStreamDescriptor::size() const { + if (empty()) + return 0u; + return kHeaderSize + length(); +} + +WiFiDisplayElementaryStreamDescriptor +WiFiDisplayElementaryStreamDescriptor::AVCTimingAndHRD::Create() { + WiFiDisplayElementaryStreamDescriptor descriptor( + DESCRIPTOR_TAG_AVC_TIMING_AND_HRD, 2u); + uint8_t* p = descriptor.private_data(); + *p++ = (false << 7) | // hrd_management_valid_flag + (0x3Fu << 1) | // reserved (all six bits on) + (false << 0); // picture_and_timing_info_present + // No picture nor timing info bits. + *p++ = (false << 7) | // fixed_frame_rate_flag + (false << 6) | // temporal_poc_flag + (false << 5) | // picture_to_display_conversion_flag + (0x1Fu << 0); // reserved (all five bits on) + DCHECK_EQ(descriptor.end(), p); + return descriptor; +} + +WiFiDisplayElementaryStreamDescriptor +WiFiDisplayElementaryStreamDescriptor::AVCVideo::Create( + uint8_t profile_idc, + bool constraint_set0_flag, + bool constraint_set1_flag, + bool constraint_set2_flag, + uint8_t avc_compatible_flags, + uint8_t level_idc, + bool avc_still_present) { + const bool avc_24_hour_picture_flag = false; + WiFiDisplayElementaryStreamDescriptor descriptor(DESCRIPTOR_TAG_AVC_VIDEO, + 4u); + uint8_t* p = descriptor.private_data(); + *p++ = profile_idc; + *p++ = (constraint_set0_flag << 7) | (constraint_set1_flag << 6) | + (constraint_set2_flag << 5) | (avc_compatible_flags << 0); + *p++ = level_idc; + *p++ = (avc_still_present << 7) | (avc_24_hour_picture_flag << 6) | + (0x3Fu << 0); // Reserved (all 6 bits on) + DCHECK_EQ(descriptor.end(), p); + return descriptor; +} + +namespace { +struct LPCMAudioStreamByte0 { + enum : uint8_t { + kBitsPerSampleShift = 3u, + kBitsPerSampleMask = ((1u << 2) - 1u) << kBitsPerSampleShift, + kEmphasisFlagShift = 0u, + kEmphasisFlagMask = 1u << kEmphasisFlagShift, + kReservedOnBitsShift = 1u, + kReservedOnBitsMask = ((1u << 2) - 1u) << kReservedOnBitsShift, + kSamplingFrequencyShift = 5u, + kSamplingFrequencyMask = ((1u << 3) - 1u) << kSamplingFrequencyShift, + }; +}; + +struct LPCMAudioStreamByte1 { + enum : uint8_t { + kNumberOfChannelsShift = 5u, + kNumberOfChannelsMask = ((1u << 3) - 1u) << kNumberOfChannelsShift, + kReservedOnBitsShift = 0u, + kReservedOnBitsMask = ((1u << 4) - 1u) << kReservedOnBitsShift, + // The bit not listed above having a shift 4u is a reserved off bit. + }; +}; +} // namespace + +WiFiDisplayElementaryStreamDescriptor +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::Create( + SamplingFrequency sampling_frequency, + BitsPerSample bits_per_sample, + bool emphasis_flag, + NumberOfChannels number_of_channels) { + WiFiDisplayElementaryStreamDescriptor descriptor( + DESCRIPTOR_TAG_LPCM_AUDIO_STREAM, 2u); + uint8_t* p = descriptor.private_data(); + *p++ = (sampling_frequency << LPCMAudioStreamByte0::kSamplingFrequencyShift) | + (bits_per_sample << LPCMAudioStreamByte0::kBitsPerSampleShift) | + LPCMAudioStreamByte0::kReservedOnBitsMask | + (emphasis_flag << LPCMAudioStreamByte0::kEmphasisFlagShift); + *p++ = (number_of_channels << LPCMAudioStreamByte1::kNumberOfChannelsShift) | + LPCMAudioStreamByte1::kReservedOnBitsMask; + DCHECK_EQ(descriptor.end(), p); + return descriptor; +} + +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::BitsPerSample +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::bits_per_sample() + const { + return static_cast<BitsPerSample>( + (private_data()[0] & LPCMAudioStreamByte0::kBitsPerSampleMask) >> + LPCMAudioStreamByte0::kBitsPerSampleShift); +} + +bool WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::emphasis_flag() + const { + return (private_data()[0] & LPCMAudioStreamByte0::kEmphasisFlagMask) != 0u; +} + +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::NumberOfChannels +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::number_of_channels() + const { + return static_cast<NumberOfChannels>( + (private_data()[1] & LPCMAudioStreamByte1::kNumberOfChannelsMask) >> + LPCMAudioStreamByte1::kNumberOfChannelsShift); +} + +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::SamplingFrequency +WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream::sampling_frequency() + const { + return static_cast<SamplingFrequency>( + (private_data()[0] & LPCMAudioStreamByte0::kSamplingFrequencyMask) >> + LPCMAudioStreamByte0::kSamplingFrequencyShift); +} + +} // namespace extensions diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h new file mode 100644 index 0000000..c149af8 --- /dev/null +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h @@ -0,0 +1,122 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_WIFI_DISPLAY_WIFI_DISPLAY_ELEMENTARY_STREAM_DESCRIPTOR_H_ +#define EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_WIFI_DISPLAY_WIFI_DISPLAY_ELEMENTARY_STREAM_DESCRIPTOR_H_ + +#include <stdint.h> +#include <type_traits> + +#include "base/memory/scoped_ptr.h" + +namespace extensions { + +// WiFi Display elementary stream descriptors are used for passing descriptive +// information about elementary streams to WiFiDisplayTransportStreamPacketizer +// which then packetizes that information so that it can be passed to a remote +// sink. +class WiFiDisplayElementaryStreamDescriptor { + public: + enum { kHeaderSize = 2u }; + + enum DescriptorTag : uint8_t { + DESCRIPTOR_TAG_AVC_VIDEO = 0x28u, + DESCRIPTOR_TAG_AVC_TIMING_AND_HRD = 0x2A, + DESCRIPTOR_TAG_LPCM_AUDIO_STREAM = 0x83u, + }; + + // Make Google Test treat this class as a container. + using const_iterator = const uint8_t*; + using iterator = const uint8_t*; + + WiFiDisplayElementaryStreamDescriptor( + const WiFiDisplayElementaryStreamDescriptor&); + WiFiDisplayElementaryStreamDescriptor( + WiFiDisplayElementaryStreamDescriptor&&); + ~WiFiDisplayElementaryStreamDescriptor(); + + WiFiDisplayElementaryStreamDescriptor& operator=( + WiFiDisplayElementaryStreamDescriptor&&); + + const uint8_t* begin() const { return data(); } + const uint8_t* data() const; + bool empty() const { return !data_; } + const uint8_t* end() const { return data() + size(); } + size_t size() const; + + DescriptorTag tag() const { return static_cast<DescriptorTag>(data()[0]); } + uint8_t length() const { return data()[1]; } + + // AVC (Advanced Video Coding) timing and HRD (Hypothetical Reference + // Decoder) descriptor provides timing and HRD parameters for a video stream. + struct AVCTimingAndHRD { + static WiFiDisplayElementaryStreamDescriptor Create(); + }; + + // AVC (Advanced Video Coding) video descriptor provides basic coding + // parameters for a video stream. + struct AVCVideo { + static WiFiDisplayElementaryStreamDescriptor Create( + uint8_t profile_idc, + bool constraint_set0_flag, + bool constraint_set1_flag, + bool constraint_set2_flag, + uint8_t avc_compatible_flags, + uint8_t level_idc, + bool avc_still_present); + }; + + class LPCMAudioStream; + + protected: + WiFiDisplayElementaryStreamDescriptor(DescriptorTag tag, uint8_t length); + + uint8_t* data(); + const uint8_t* private_data() const { return data() + kHeaderSize; } + uint8_t* private_data() { return data() + kHeaderSize; } + + private: + scoped_ptr<uint8_t[]> data_; +}; + +// LPCM (Linear pulse-code modulation) audio stream descriptor provides basic +// coding parameters for a private WiFi Display LPCM audio stream. +class WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream + : public WiFiDisplayElementaryStreamDescriptor { + public: + enum { kTag = DESCRIPTOR_TAG_LPCM_AUDIO_STREAM }; + enum BitsPerSample : uint8_t { BITS_PER_SAMPLE_16 = 0u }; + enum NumberOfChannels : uint8_t { + NUMBER_OF_CHANNELS_DUAL_MONO = 0u, + NUMBER_OF_CHANNELS_STEREO = 1u + }; + enum SamplingFrequency : uint8_t { + SAMPLING_FREQUENCY_44_1K = 1u, + SAMPLING_FREQUENCY_48K = 2u + }; + + static WiFiDisplayElementaryStreamDescriptor Create( + SamplingFrequency sampling_frequency, + BitsPerSample bits_per_sample, + bool emphasis_flag, + NumberOfChannels number_of_channels); + + BitsPerSample bits_per_sample() const; + bool emphasis_flag() const; + NumberOfChannels number_of_channels() const; + SamplingFrequency sampling_frequency() const; +}; + +// Subclasses of WiFiDisplayElementaryStreamDescriptor MUST NOT define new +// member variables but only new non-virtual member functions which parse +// the inherited data. This allows WiFiDisplayElementaryStreamDescriptor +// pointers to be cast to subclass pointers. +static_assert( + std::is_standard_layout< + WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream>::value, + "Forbidden memory layout for an elementary stream descriptor"); + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_API_DISPLAY_SOURCE_WIFI_DISPLAY_WIFI_DISPLAY_ELEMENTARY_STREAM_DESCRIPTOR_H_ diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc new file mode 100644 index 0000000..4e049db --- /dev/null +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc @@ -0,0 +1,151 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h" + +#include <algorithm> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" + +using LPCMAudioStreamDescriptor = + extensions::WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream; + +namespace extensions { + +namespace { + +// Copy constructors cannot always be tested by calling them directly as +// a compiler is allowed to optimize copy constructor calls away in certain +// cases (that is called return value optimization). Therefore, this helper +// function is needed to really create a copy of an object. +template <typename T> +T Copy(const T& t) { + return t; +} + +class Data : public std::vector<uint8_t> { + public: + template <size_t N> + explicit Data(const char (&str)[N]) { + EXPECT_EQ('\0', str[N - 1]); + insert(end(), str, str + N - 1); + } + + bool operator==(const WiFiDisplayElementaryStreamDescriptor& rhs) const { + return size() == rhs.size() && std::equal(begin(), end(), rhs.begin()); + } +}; + +TEST(WiFiDisplayElementaryStreamDescriptorTest, AVCTimingAndHRDDescriptor) { + using AVCTimingAndHRDDescriptor = + WiFiDisplayElementaryStreamDescriptor::AVCTimingAndHRD; + EXPECT_EQ(Data("\x2A\x02\x7E\x1F"), AVCTimingAndHRDDescriptor::Create()); + EXPECT_EQ(Data("\x2A\x02\x7E\x1F"), + Copy(AVCTimingAndHRDDescriptor::Create())); +} + +TEST(WiFiDisplayElementaryStreamDescriptorTest, AVCVideoDescriptor) { + using AVCVideoDescriptor = WiFiDisplayElementaryStreamDescriptor::AVCVideo; + EXPECT_EQ( + Data("\x28\x04\x00\x00\x00\x3F"), + AVCVideoDescriptor::Create(0x0u, false, false, false, 0x0u, 0x0u, false)); + EXPECT_EQ(Data("\x28\x04\x00\x00\x00\x3F"), + Copy(AVCVideoDescriptor::Create(0x0u, false, false, false, 0x0u, + 0x0u, false))); + EXPECT_EQ(Data("\x28\x04\xFF\x00\x00\x3F"), + AVCVideoDescriptor::Create(0xFFu, false, false, false, 0x0u, 0x0u, + false)); + EXPECT_EQ( + Data("\x28\x04\x00\x80\x00\x3F"), + AVCVideoDescriptor::Create(0x0u, true, false, false, 0x0u, 0x0u, false)); + EXPECT_EQ( + Data("\x28\x04\x00\x40\x00\x3F"), + AVCVideoDescriptor::Create(0x0u, false, true, false, 0x0u, 0x0u, false)); + EXPECT_EQ( + Data("\x28\x04\x00\x20\x00\x3F"), + AVCVideoDescriptor::Create(0x0u, false, false, true, 0x0u, 0x0u, false)); + EXPECT_EQ(Data("\x28\x04\x00\x1F\x00\x3F"), + AVCVideoDescriptor::Create(0x0u, false, false, false, 0x1Fu, 0x0u, + false)); + EXPECT_EQ(Data("\x28\x04\x00\x00\xFF\x3F"), + AVCVideoDescriptor::Create(0x0u, false, false, false, 0x0u, 0xFFu, + false)); + EXPECT_EQ( + Data("\x28\x04\x00\x00\x00\xBF"), + AVCVideoDescriptor::Create(0x0u, false, false, false, 0x0u, 0x0u, true)); +} + +class LPCMAudioStreamDescriptorTest + : public testing::TestWithParam< + testing::tuple<LPCMAudioStreamDescriptor::SamplingFrequency, + LPCMAudioStreamDescriptor::BitsPerSample, + bool, + LPCMAudioStreamDescriptor::NumberOfChannels, + Data>> { + protected: + LPCMAudioStreamDescriptorTest() + : sampling_frequency_(testing::get<0>(GetParam())), + bits_per_sample_(testing::get<1>(GetParam())), + emphasis_flag_(testing::get<2>(GetParam())), + number_of_channels_(testing::get<3>(GetParam())), + expected_data_(testing::get<4>(GetParam())), + descriptor_(LPCMAudioStreamDescriptor::Create(sampling_frequency_, + bits_per_sample_, + emphasis_flag_, + number_of_channels_)) {} + + const LPCMAudioStreamDescriptor::SamplingFrequency sampling_frequency_; + const LPCMAudioStreamDescriptor::BitsPerSample bits_per_sample_; + const bool emphasis_flag_; + const LPCMAudioStreamDescriptor::NumberOfChannels number_of_channels_; + const Data expected_data_; + const WiFiDisplayElementaryStreamDescriptor descriptor_; +}; + +TEST_P(LPCMAudioStreamDescriptorTest, Create) { + EXPECT_EQ(expected_data_, descriptor_); + EXPECT_EQ(expected_data_, Copy(descriptor_)); +} + +TEST_P(LPCMAudioStreamDescriptorTest, Accessors) { + ASSERT_EQ(LPCMAudioStreamDescriptor::kTag, descriptor_.tag()); + const LPCMAudioStreamDescriptor& descriptor = + *static_cast<const LPCMAudioStreamDescriptor*>(&descriptor_); + EXPECT_EQ(sampling_frequency_, descriptor.sampling_frequency()); + EXPECT_EQ(bits_per_sample_, descriptor.bits_per_sample()); + EXPECT_EQ(emphasis_flag_, descriptor.emphasis_flag()); + EXPECT_EQ(number_of_channels_, descriptor.number_of_channels()); +} + +INSTANTIATE_TEST_CASE_P( + WiFiDisplayElementaryStreamDescriptorTests, + LPCMAudioStreamDescriptorTest, + testing::Values(testing::make_tuple( + LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_44_1K, + LPCMAudioStreamDescriptor::BITS_PER_SAMPLE_16, + false, + LPCMAudioStreamDescriptor::NUMBER_OF_CHANNELS_DUAL_MONO, + Data("\x83\x02\x26\x0F")), + testing::make_tuple( + LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_48K, + LPCMAudioStreamDescriptor::BITS_PER_SAMPLE_16, + false, + LPCMAudioStreamDescriptor::NUMBER_OF_CHANNELS_DUAL_MONO, + Data("\x83\x02\x46\x0F")), + testing::make_tuple( + LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_44_1K, + LPCMAudioStreamDescriptor::BITS_PER_SAMPLE_16, + true, + LPCMAudioStreamDescriptor::NUMBER_OF_CHANNELS_DUAL_MONO, + Data("\x83\x02\x27\x0F")), + testing::make_tuple( + LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_44_1K, + LPCMAudioStreamDescriptor::BITS_PER_SAMPLE_16, + false, + LPCMAudioStreamDescriptor::NUMBER_OF_CHANNELS_STEREO, + Data("\x83\x02\x26\x2F")))); + +} // namespace +} // namespace extensions |