Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Unified Diff: extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc

Issue 1797953002: Implement WiFi Display transport stream packetizer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
index a8b769a4421ace00b07782a61c9e5344a614f764..4ba1969bad48618cbf32d3a4fb28d868fb87a6eb 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
@@ -2,12 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <list>
+
#include "base/big_endian.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_info.h"
#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_packetizer.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.h"
#include "testing/gtest/include/gtest/gtest.h"
+using PacketPart = extensions::WiFiDisplayStreamPacketPart;
+
namespace extensions {
+std::ostream& operator<<(std::ostream& os, const PacketPart& part) {
+ const auto flags = os.flags();
+ os << "{" << std::hex << std::noshowbase;
+ for (const auto& item : part) {
+ if (&item != &*part.begin())
+ os << ", ";
+ os << "0x" << static_cast<unsigned>(item);
+ }
+ os.setf(flags, std::ios::basefield | std::ios::showbase);
+ return os << "}";
+}
+
+bool operator==(const PacketPart& a, const PacketPart& b) {
+ if (a.size() != b.size())
+ return false;
+ return std::equal(a.begin(), a.end(), b.begin());
+}
+
namespace {
namespace pes {
@@ -17,6 +42,108 @@ const unsigned kPtsFlag = 0x0080u;
const size_t kUnitDataAlignment = sizeof(uint32_t);
}
+namespace ts {
+const uint64_t kTimeStampMask = (static_cast<uint64_t>(1u) << 33) - 1u;
+const uint64_t kTimeStampSecond = 90000u; // 90 kHz
+const uint64_t kProgramClockReferenceSecond =
+ 300u * kTimeStampSecond; // 27 MHz
+
+// Packet header:
+const size_t kPacketHeaderSize = 4u;
+const unsigned kSyncByte = 0x47u;
+const uint32_t kSyncByteMask = 0xFF000000u;
+const uint32_t kTransportErrorIndicator = 0x00800000u;
+const uint32_t kPayloadUnitStartIndicator = 0x00400000u;
+const uint32_t kTransportPriority = 0x00200000u;
+const uint32_t kScramblingControlMask = 0x000000C0u;
+const uint32_t kAdaptationFieldFlag = 0x00000020u;
+const uint32_t kPayloadFlag = 0x00000010u;
+
+// Adaptation field:
+const unsigned kRandomAccessFlag = 0x40u;
+const unsigned kPcrFlag = 0x10u;
+} // namespace ts
+
+namespace widi {
+const unsigned kProgramAssociationTablePacketId = 0x0000u;
+const unsigned kProgramMapTablePacketId = 0x0100u;
+const unsigned kProgramClockReferencePacketId = 0x1000u;
+const unsigned kVideoStreamPacketId = 0x1011u;
+const unsigned kFirstAudioStreamPacketId = 0x1100u;
+} // namespace widi
+
+template <typename PacketContainer>
+class PacketCollector {
+ public:
+ PacketContainer FetchPackets() {
+ PacketContainer container;
+ container.swap(packets_);
+ return container;
+ }
+
+ protected:
+ PacketContainer packets_;
+};
+
+class FakeTransportStreamPacketizer
+ : public WiFiDisplayTransportStreamPacketizer,
+ public PacketCollector<std::list<WiFiDisplayTransportStreamPacket>> {
+ public:
+ FakeTransportStreamPacketizer(
+ const base::TimeDelta& delay_for_unit_time_stamps,
+ std::vector<WiFiDisplayElementaryStreamInfo> stream_infos)
+ : WiFiDisplayTransportStreamPacketizer(delay_for_unit_time_stamps,
+ std::move(stream_infos)) {}
+
+ using WiFiDisplayTransportStreamPacketizer::NormalizeUnitTimeStamps;
+
+ protected:
+ bool OnPacketizedTransportStreamPacket(
+ const WiFiDisplayTransportStreamPacket& transport_stream_packet,
+ bool flush) override {
+ // Make a copy of header bytes as they are in stack.
+ headers_.emplace_back(transport_stream_packet.header().begin(),
+ transport_stream_packet.header().end());
+ const auto& header = headers_.back();
+ if (transport_stream_packet.payload().empty()) {
+ packets_.emplace_back(header.data(), header.size());
+ } else {
+ packets_.emplace_back(header.data(), header.size(),
+ transport_stream_packet.payload().begin());
+ }
+ EXPECT_EQ(transport_stream_packet.header().size(),
+ packets_.back().header().size());
+ EXPECT_EQ(transport_stream_packet.payload().size(),
+ packets_.back().payload().size());
+ EXPECT_EQ(transport_stream_packet.filler().size(),
+ packets_.back().filler().size());
+ return true;
+ }
+
+ private:
+ std::vector<std::vector<uint8_t>> headers_;
+};
+
+struct ProgramClockReference {
+ enum { kInvalidBase = ~static_cast<uint64_t>(0u) };
+ uint64_t base;
+ uint16_t extension;
+};
+
+ProgramClockReference ParseProgramClockReference(const uint8_t pcr_bytes[6]) {
+ const uint8_t reserved_pcr_bits = pcr_bytes[4] & 0x7Eu;
+ EXPECT_EQ(0x7Eu, reserved_pcr_bits);
+ ProgramClockReference pcr;
+ pcr.base = pcr_bytes[0];
+ pcr.base = (pcr.base << 8) | pcr_bytes[1];
+ pcr.base = (pcr.base << 8) | pcr_bytes[2];
+ pcr.base = (pcr.base << 8) | pcr_bytes[3];
+ pcr.base = (pcr.base << 1) | ((pcr_bytes[4] & 0x80u) >> 7);
+ pcr.extension = pcr_bytes[4] & 0x01u;
+ pcr.extension = (pcr.extension << 8) | pcr_bytes[5];
+ return pcr;
+}
+
uint64_t ParseTimeStamp(const uint8_t ts_bytes[5], uint8_t pts_dts_indicator) {
EXPECT_EQ(pts_dts_indicator, (ts_bytes[0] & 0xF0u) >> 4);
EXPECT_EQ(0x01u, ts_bytes[0] & 0x01u);
@@ -31,6 +158,14 @@ uint64_t ParseTimeStamp(const uint8_t ts_bytes[5], uint8_t pts_dts_indicator) {
return ts;
}
+unsigned ParseTransportStreamPacketId(
+ const WiFiDisplayTransportStreamPacket& packet) {
+ if (packet.header().size() < ts::kPacketHeaderSize)
+ return ~0u;
+ return (((packet.header().begin()[1] & 0x001Fu) << 8) |
+ packet.header().begin()[2]);
+}
+
class WiFiDisplayElementaryStreamUnitPacketizationTest
: public testing::TestWithParam<
testing::tuple<unsigned, base::TimeDelta, base::TimeDelta>> {
@@ -120,12 +255,268 @@ class WiFiDisplayElementaryStreamUnitPacketizationTest
EXPECT_EQ(unit_.size(), packet.unit().size());
}
+ void CheckTransportStreamPacketHeader(
+ base::BigEndianReader* header_reader,
+ bool expected_payload_unit_start_indicator,
+ unsigned expected_packet_id,
+ bool* adaptation_field_flag,
+ uint8_t expected_continuity_counter) {
+ uint32_t parsed_u32;
+ EXPECT_TRUE(header_reader->ReadU32(&parsed_u32));
+ EXPECT_EQ(ts::kSyncByte << 24u, parsed_u32 & ts::kSyncByteMask);
+ EXPECT_EQ(0x0u, parsed_u32 & ts::kTransportErrorIndicator);
+ EXPECT_EQ(expected_payload_unit_start_indicator,
+ (parsed_u32 & ts::kPayloadUnitStartIndicator) != 0u);
+ EXPECT_EQ(0x0u, parsed_u32 & ts::kTransportPriority);
+ EXPECT_EQ(expected_packet_id, (parsed_u32 & 0x001FFF00) >> 8);
+ EXPECT_EQ(0x0u, parsed_u32 & ts::kScramblingControlMask);
+ if (!adaptation_field_flag) {
+ EXPECT_EQ(0x0u, parsed_u32 & ts::kAdaptationFieldFlag);
+ } else {
+ *adaptation_field_flag = (parsed_u32 & ts::kAdaptationFieldFlag) != 0u;
+ }
+ EXPECT_EQ(ts::kPayloadFlag, parsed_u32 & ts::kPayloadFlag);
+ EXPECT_EQ(expected_continuity_counter & 0xFu, parsed_u32 & 0x0000000Fu);
+ }
+
+ void CheckTransportStreamAdaptationField(
+ base::BigEndianReader* header_reader,
+ const WiFiDisplayTransportStreamPacket& packet,
+ uint8_t* adaptation_field_flags) {
+ uint8_t parsed_adaptation_field_length;
+ EXPECT_TRUE(header_reader->ReadU8(&parsed_adaptation_field_length));
+ if (parsed_adaptation_field_length > 0u) {
+ const int initial_remaining = header_reader->remaining();
+ uint8_t parsed_adaptation_field_flags;
+ EXPECT_TRUE(header_reader->ReadU8(&parsed_adaptation_field_flags));
+ if (!adaptation_field_flags) {
+ EXPECT_EQ(0x0u, parsed_adaptation_field_flags);
+ } else {
+ *adaptation_field_flags = parsed_adaptation_field_flags;
+ if (parsed_adaptation_field_flags & ts::kPcrFlag) {
+ uint8_t parsed_pcr_bytes[6];
+ EXPECT_TRUE(header_reader->ReadBytes(parsed_pcr_bytes,
+ sizeof(parsed_pcr_bytes)));
+ parsed_pcr_ = ParseProgramClockReference(parsed_pcr_bytes);
+ }
+ }
+ size_t remaining_stuffing_length =
+ parsed_adaptation_field_length -
+ static_cast<size_t>(initial_remaining - header_reader->remaining());
+ while (remaining_stuffing_length > 0u && header_reader->remaining() > 0) {
+ // Adaptation field stuffing byte in header_reader.
+ uint8_t parsed_stuffing_byte;
+ EXPECT_TRUE(header_reader->ReadU8(&parsed_stuffing_byte));
+ EXPECT_EQ(0xFFu, parsed_stuffing_byte);
+ --remaining_stuffing_length;
+ }
+ if (packet.payload().empty()) {
+ // Adaptation field stuffing bytes in packet.filler().
+ EXPECT_EQ(remaining_stuffing_length, packet.filler().size());
+ EXPECT_EQ(0xFFu, packet.filler().value());
+ } else {
+ EXPECT_EQ(0u, remaining_stuffing_length);
+ }
+ }
+ }
+
+ void CheckTransportStreamProgramAssociationTablePacket(
+ const WiFiDisplayTransportStreamPacket& packet) {
+ static const uint8_t kProgramAssicationTable[4u + 13u] = {
+ // Pointer:
+ 0u, // Pointer field
+ // Table header:
+ 0x00u, // Table ID (PAT)
+ 0x80u | // Section syntax indicator (0b1 for PAT)
+ 0x00u | // Private bit (0b0 for PAT)
+ 0x30u | // Reserved bits (0b11)
+ 0x00u | // Section length unused bits (0b00)
+ 0u, // Section length (10 bits)
+ 13u, //
+ // Table syntax:
+ 0x00u, // Table ID extension (transport stream ID)
+ 0x01u, //
+ 0xC0u | // Reserved bits (0b11)
+ 0x00u | // Version (0b00000)
+ 0x01u, // Current indicator (0b1)
+ 0u, // Section number
+ 0u, // Last section number
+ // Program association table specific data:
+ 0x00u, // Program number
+ 0x01u, //
+ 0xE0 | // Reserved bits (0b111)
+ 0x01u, // Program map packet ID (13 bits)
+ 0x00, //
+ // CRC:
+ 0xE8u,
+ 0xF9u, 0x5Eu, 0x7Du};
+
+ base::BigEndianReader header_reader(
+ reinterpret_cast<const char*>(packet.header().begin()),
+ packet.header().size());
+
+ CheckTransportStreamPacketHeader(
+ &header_reader, true, widi::kProgramAssociationTablePacketId, nullptr,
+ continuity_.program_assication_table++);
+
+ EXPECT_EQ(PacketPart(kProgramAssicationTable),
+ PacketPart(packet.header().end() - header_reader.remaining(),
+ static_cast<size_t>(header_reader.remaining())));
+ EXPECT_TRUE(header_reader.Skip(header_reader.remaining()));
+
+ EXPECT_EQ(0, header_reader.remaining());
+ EXPECT_EQ(0u, packet.payload().size());
+ }
+
+ void CheckTransportStreamProgramMapTablePacket(
+ const WiFiDisplayTransportStreamPacket& packet,
+ const PacketPart& program_map_table) {
+ base::BigEndianReader header_reader(
+ reinterpret_cast<const char*>(packet.header().begin()),
+ packet.header().size());
+
+ CheckTransportStreamPacketHeader(&header_reader, true,
+ widi::kProgramMapTablePacketId, nullptr,
+ continuity_.program_map_table++);
+
+ EXPECT_EQ(program_map_table,
+ PacketPart(packet.header().end() - header_reader.remaining(),
+ static_cast<size_t>(header_reader.remaining())));
+ EXPECT_TRUE(header_reader.Skip(header_reader.remaining()));
+
+ EXPECT_EQ(0, header_reader.remaining());
+ EXPECT_EQ(0u, packet.payload().size());
+ }
+
+ void CheckTransportStreamProgramClockReferencePacket(
+ const WiFiDisplayTransportStreamPacket& packet) {
+ base::BigEndianReader header_reader(
+ reinterpret_cast<const char*>(packet.header().begin()),
+ packet.header().size());
+
+ bool parsed_adaptation_field_flag;
+ CheckTransportStreamPacketHeader(
+ &header_reader, true, widi::kProgramClockReferencePacketId,
+ &parsed_adaptation_field_flag, continuity_.program_clock_reference++);
+ EXPECT_TRUE(parsed_adaptation_field_flag);
+
+ uint8_t parsed_adaptation_field_flags;
+ CheckTransportStreamAdaptationField(&header_reader, packet,
+ &parsed_adaptation_field_flags);
+ EXPECT_EQ(ts::kPcrFlag, parsed_adaptation_field_flags);
+
+ EXPECT_EQ(0, header_reader.remaining());
+ EXPECT_EQ(0u, packet.payload().size());
+ }
+
+ void CheckTransportStreamElementaryStreamPacket(
+ const WiFiDisplayTransportStreamPacket& packet,
+ const WiFiDisplayElementaryStreamPacket& elementary_stream_packet,
+ unsigned stream_index,
+ unsigned expected_packet_id,
+ bool expected_random_access,
+ const uint8_t** unit_data_pos) {
+ const bool first_transport_stream_packet_for_current_unit =
+ packet.payload().begin() == unit_.data();
+ const bool last_transport_stream_packet_for_current_unit =
+ packet.payload().end() == unit_.data() + unit_.size();
+ base::BigEndianReader header_reader(
+ reinterpret_cast<const char*>(packet.header().begin()),
+ packet.header().size());
+
+ bool parsed_adaptation_field_flag;
+ CheckTransportStreamPacketHeader(
+ &header_reader, first_transport_stream_packet_for_current_unit,
+ expected_packet_id, &parsed_adaptation_field_flag,
+ continuity_.elementary_streams[stream_index]++);
+
+ if (first_transport_stream_packet_for_current_unit) {
+ // Random access can only be signified by adaptation field.
+ if (expected_random_access)
+ EXPECT_TRUE(parsed_adaptation_field_flag);
+ // If there is no need for padding nor for a random access indicator,
+ // then there is no need for an adaptation field, either.
+ if (!last_transport_stream_packet_for_current_unit &&
+ !expected_random_access) {
+ EXPECT_FALSE(parsed_adaptation_field_flag);
+ }
+ if (parsed_adaptation_field_flag) {
+ uint8_t parsed_adaptation_field_flags;
+ CheckTransportStreamAdaptationField(&header_reader, packet,
+ &parsed_adaptation_field_flags);
+ EXPECT_EQ(expected_random_access ? ts::kRandomAccessFlag : 0u,
+ parsed_adaptation_field_flags);
+ }
+
+ // Elementary stream header.
+ PacketPart parsed_elementary_stream_packet_header(
+ packet.header().end() - header_reader.remaining(),
+ std::min(elementary_stream_packet.header().size(),
+ static_cast<size_t>(header_reader.remaining())));
+ EXPECT_EQ(elementary_stream_packet.header(),
+ parsed_elementary_stream_packet_header);
+ EXPECT_TRUE(
+ header_reader.Skip(parsed_elementary_stream_packet_header.size()));
+
+ // Elementary stream unit header.
+ PacketPart parsed_unit_header(
+ packet.header().end() - header_reader.remaining(),
+ std::min(elementary_stream_packet.unit_header().size(),
+ static_cast<size_t>(header_reader.remaining())));
+ EXPECT_EQ(elementary_stream_packet.unit_header(), parsed_unit_header);
+ EXPECT_TRUE(header_reader.Skip(parsed_unit_header.size()));
+
+ // Time stamps.
+ if (parsed_elementary_stream_packet_header.size() >= 19u) {
+ uint64_t parsed_dts = ParseTimeStamp(
+ &parsed_elementary_stream_packet_header.begin()[14], 0x1u);
+ // Check that
+ // 0 <= 300 * parsed_dts - parsed_pcr_value <=
+ // kProgramClockReferenceSecond
+ // where
+ // parsed_pcr_value = 300 * parsed_pcr_.base + parsed_pcr_.extension
+ // but allow parsed_pcr_.base and parsed_dts to wrap around in 33 bits.
+ EXPECT_NE(ProgramClockReference::kInvalidBase, parsed_pcr_.base);
+ EXPECT_LE(
+ 300u * ((parsed_dts - parsed_pcr_.base) & ts::kTimeStampMask) -
+ parsed_pcr_.extension,
+ ts::kProgramClockReferenceSecond)
+ << " DTS must be not smaller than PCR!";
+ }
+ } else {
+ // If there is no need for padding, then there is no need for
+ // an adaptation field, either.
+ if (!last_transport_stream_packet_for_current_unit)
+ EXPECT_FALSE(parsed_adaptation_field_flag);
+ if (parsed_adaptation_field_flag) {
+ CheckTransportStreamAdaptationField(&header_reader, packet, nullptr);
+ }
+ }
+ EXPECT_EQ(0, header_reader.remaining());
+
+ // Transport stream packet payload.
+ EXPECT_EQ(*unit_data_pos, packet.payload().begin());
+ if (*unit_data_pos == packet.payload().begin())
+ *unit_data_pos += packet.payload().size();
+
+ // Transport stream packet filler.
+ EXPECT_EQ(0u, packet.filler().size());
+ }
+
enum { kVideoOnlyUnitSize = 0x8000u }; // Not exact. Be on the safe side.
const std::vector<uint8_t> unit_;
const base::TimeTicks now_;
const base::TimeTicks dts_;
const base::TimeTicks pts_;
+
+ struct {
+ size_t program_assication_table;
+ size_t program_map_table;
+ size_t program_clock_reference;
+ size_t elementary_streams[3];
+ } continuity_ = {0u, 0u, 0u, {0u, 0u, 0u}};
+ ProgramClockReference parsed_pcr_ = {ProgramClockReference::kInvalidBase, 0u};
};
TEST_P(WiFiDisplayElementaryStreamUnitPacketizationTest,
@@ -152,6 +543,163 @@ TEST_P(WiFiDisplayElementaryStreamUnitPacketizationTest,
}
}
+TEST_P(WiFiDisplayElementaryStreamUnitPacketizationTest,
+ EncodeToTransportStreamPackets) {
+ enum { kStreamCount = 3u };
+ static const bool kBoolValues[] = {false, true};
+ static const unsigned kPacketIds[kStreamCount] = {
+ widi::kVideoStreamPacketId, widi::kFirstAudioStreamPacketId + 0u,
+ widi::kFirstAudioStreamPacketId + 1u};
+ static const uint8_t kProgramMapTable[4u + 42u] = {
+ // Pointer:
+ 0u, // Pointer field
+ // Table header:
+ 0x02u, // Table ID (PMT)
+ 0x80u | // Section syntax indicator (0b1 for PMT)
+ 0x00u | // Private bit (0b0 for PMT)
+ 0x30u | // Reserved bits (0b11)
+ 0x00u | // Section length unused bits (0b00)
+ 0u, // Section length (10 bits)
+ 42u, //
+ // Table syntax:
+ 0x00u, // Table ID extension (program number)
+ 0x01u, //
+ 0xC0u | // Reserved bits (0b11)
+ 0x00u | // Version (0b00000)
+ 0x01u, // Current indicator (0b1)
+ 0u, // Section number
+ 0u, // Last section number
+ // Program map table specific data:
+ 0xE0u | // Reserved bits (0b111)
+ 0x10u, // Program clock reference packet ID (13 bits)
+ 0x00u, //
+ 0xF0u | // Reserved bits (0b11)
+ 0x00u | // Program info length unused bits
+ 0u, // Program info length (10 bits)
+ 0u, //
+ // Elementary stream specific data:
+ 0x1Bu, // Stream type (H.264 in a packetized stream)
+ 0xE0u | // Reserved bits (0b111)
+ 0x10u, // Elementary packet ID (13 bits)
+ 0x11u, //
+ 0xF0u | // Reserved bits (0b1111)
+ 0x00u | // Elementary stream info length unused bits
+ 0u, // Elementary stream info length (10 bits)
+ 10u, //
+ 0x28u, // AVC video descriptor tag
+ 4u, // Descriptor length
+ 0xA5u,
+ 0xF5u, 0xBDu, 0xBFu,
+ 0x2Au, // AVC timing and HRD descriptor tag
+ 2u, // Descriptor length
+ 0x7Eu, 0x1Fu,
+ // Elementary stream specific data:
+ 0x83u, // Stream type (lossless audio in a packetized stream)
+ 0xE0u | // Reserved bits (0b111)
+ 0x11u, // Elementary packet ID (13 bits)
+ 0x00u, //
+ 0xF0u | // Reserved bits (0b1111)
+ 0x00u | // Elementary stream info length unused bits
+ 0u, // Elementary stream info length (10 bits)
+ 4u, //
+ 0x83u, // LPCM audio stream descriptor tag
+ 2u, // Descriptor length
+ 0x26u,
+ 0x2Fu,
+ // Elementary stream specific data:
+ 0x0Fu, // Stream type (AAC in a packetized stream)
+ 0xE0u | // Reserved bits (0b111)
+ 0x11u, // Elementary packet ID (13 bits)
+ 0x01u, //
+ 0xF0u | // Reserved bits (0b1111)
+ 0x00u | // Elementary stream info length unused bits
+ 0u, // Elementary stream info length (10 bits)
+ 0u, //
+ // CRC:
+ 0x4Fu,
+ 0x63u, 0xABu, 0x6Eu};
+ static const uint8_t kStreamIds[] = {
+ WiFiDisplayElementaryStreamPacketizer::kFirstVideoStreamId,
+ WiFiDisplayElementaryStreamPacketizer::kPrivateStream1Id,
+ WiFiDisplayElementaryStreamPacketizer::kFirstAudioStreamId};
+
+ using ESDescriptor = WiFiDisplayElementaryStreamDescriptor;
+ std::vector<ESDescriptor> lpcm_descriptors;
+ lpcm_descriptors.emplace_back(ESDescriptor::LPCMAudioStream::Create(
+ ESDescriptor::LPCMAudioStream::SAMPLING_FREQUENCY_44_1K,
+ ESDescriptor::LPCMAudioStream::BITS_PER_SAMPLE_16, false,
+ ESDescriptor::LPCMAudioStream::NUMBER_OF_CHANNELS_STEREO));
+ std::vector<ESDescriptor> video_desciptors;
+ video_desciptors.emplace_back(ESDescriptor::AVCVideo::Create(
+ 0xA5u, true, true, true, 0x15u, 0xBDu, true));
+ video_desciptors.emplace_back(ESDescriptor::AVCTimingAndHRD::Create());
+ std::vector<WiFiDisplayElementaryStreamInfo> stream_infos;
+ stream_infos.emplace_back(WiFiDisplayElementaryStreamInfo::VIDEO_H264,
+ std::move(video_desciptors));
+ stream_infos.emplace_back(WiFiDisplayElementaryStreamInfo::AUDIO_LPCM,
+ std::move(lpcm_descriptors));
+ stream_infos.emplace_back(WiFiDisplayElementaryStreamInfo::AUDIO_AAC);
+ WiFiDisplayElementaryStreamPacketizer elementary_stream_packetizer;
+ FakeTransportStreamPacketizer packetizer(
+ base::TimeDelta::FromMilliseconds(200), std::move(stream_infos));
+
+ size_t packet_index = 0u;
+ for (unsigned stream_index = 0; stream_index < kStreamCount; ++stream_index) {
+ const uint8_t* unit_header_data = nullptr;
+ size_t unit_header_size = 0u;
+ if (stream_index > 0u) { // Audio stream.
+ if (unit_.size() >= kVideoOnlyUnitSize)
+ continue;
+ if (stream_index == 1u) { // LPCM
+ unit_header_data = reinterpret_cast<const uint8_t*>("\xA0\x06\x00\x09");
+ unit_header_size = 4u;
+ }
+ }
+ for (const bool random_access : kBoolValues) {
+ EXPECT_TRUE(packetizer.EncodeElementaryStreamUnit(
+ stream_index, unit_.data(), unit_.size(), random_access, pts_, dts_,
+ true));
+ auto normalized_pts = pts_;
+ auto normalized_dts = dts_;
+ packetizer.NormalizeUnitTimeStamps(&normalized_pts, &normalized_dts);
+ WiFiDisplayElementaryStreamPacket elementary_stream_packet =
+ elementary_stream_packetizer.EncodeElementaryStreamUnit(
+ kStreamIds[stream_index], unit_header_data, unit_header_size,
+ unit_.data(), unit_.size(), normalized_pts, normalized_dts);
+
+ const uint8_t* unit_data_pos = unit_.data();
+ for (const auto& packet : packetizer.FetchPackets()) {
+ switch (ParseTransportStreamPacketId(packet)) {
+ case widi::kProgramAssociationTablePacketId:
+ if (packet_index < 4u)
+ EXPECT_EQ(0u, packet_index);
+ CheckTransportStreamProgramAssociationTablePacket(packet);
+ break;
+ case widi::kProgramMapTablePacketId:
+ if (packet_index < 4u)
+ EXPECT_EQ(1u, packet_index);
+ CheckTransportStreamProgramMapTablePacket(
+ packet, PacketPart(kProgramMapTable));
+ break;
+ case widi::kProgramClockReferencePacketId:
+ if (packet_index < 4u)
+ EXPECT_EQ(2u, packet_index);
+ CheckTransportStreamProgramClockReferencePacket(packet);
+ break;
+ default:
+ if (packet_index < 4u)
+ EXPECT_EQ(3u, packet_index);
+ CheckTransportStreamElementaryStreamPacket(
+ packet, elementary_stream_packet, stream_index,
+ kPacketIds[stream_index], random_access, &unit_data_pos);
+ }
+ ++packet_index;
+ }
+ EXPECT_EQ(unit_.data() + unit_.size(), unit_data_pos);
+ }
+ }
+}
+
INSTANTIATE_TEST_CASE_P(
WiFiDisplayElementaryStreamUnitPacketizationTests,
WiFiDisplayElementaryStreamUnitPacketizationTest,

Powered by Google App Engine
This is Rietveld 408576698