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

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

Issue 1796123002: Implement WiFi Display elementary 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_elementary_stream_packetizer.cc
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_packetizer.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_packetizer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..39a6e3fcaf8daea049aa38353c0c0019c71c10b6
--- /dev/null
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_packetizer.cc
@@ -0,0 +1,188 @@
+// 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_packetizer.h"
+
+#include <cstring>
+
+#include "base/logging.h"
+
+namespace extensions {
+namespace {
+
+// Code and parameters related to the Packetized Elementary Stream (PES)
+// specification.
+namespace pes {
+
+const size_t kOptionalHeaderBaseSize = 3u;
+const size_t kPacketHeaderBaseSize = 6u;
+const size_t kTimeStampSize = 5u;
+const size_t kPacketHeaderMaxSize =
+ kPacketHeaderBaseSize + kOptionalHeaderBaseSize + 2u * kTimeStampSize;
+
+const size_t kUnitDataAlignment = 4u;
+
+size_t FillInTimeStamp(uint8_t* dst,
+ uint8_t pts_dts_indicator,
+ const base::TimeTicks& ts) {
+ // Convert to the number of 90 kHz ticks since some epoch.
+ // Always round up so that the number of ticks is never smaller than
+ // the number of program clock reference base ticks (which is not rounded
+ // because program clock reference is encoded with higher precision).
+ const uint64_t us =
+ static_cast<uint64_t>((ts - base::TimeTicks()).InMicroseconds());
+ const uint64_t n = (us * 90u + 999u) / 1000u;
+
+ // Expand PTS DTS indicator and a 33 bit time stamp to 40 bits:
+ // * 4 PTS DTS indicator bits, 3 time stamp bits, 1 on bit
+ // * 15 time stamp bits, 1 on bit
+ // * 15 time stamp bits, 1 on bit
+ size_t i = 0u;
+ dst[i++] = (pts_dts_indicator << 4) | (((n >> 30) & 0x7u) << 1) | (0x1u << 0);
+ dst[i++] = (n >> 22) & 0xFFu;
+ dst[i++] = (((n >> 15) & 0x7Fu) << 1) | (0x1u << 0);
+ dst[i++] = (n >> 7) & 0xFFu;
+ dst[i++] = (((n >> 0) & 0x7Fu) << 1) | (0x1u << 0);
+ DCHECK_EQ(i, kTimeStampSize);
+ return i;
+}
+
+size_t FillInOptionalHeader(uint8_t* dst,
+ const base::TimeTicks& pts,
+ const base::TimeTicks& dts,
+ size_t unit_header_size) {
+ size_t i = 0u;
+ dst[i++] = (0x2u << 6) | // Marker bits (0b10)
+ (0x0u << 4) | // Scrambling control (0b00 for not)
+ (0x0u << 3) | // Priority
+ (0x0u << 2) | // Data alignment indicator (0b0 for not)
+ (0x0u << 1) | // Copyright (0b0 for not)
+ (0x0u << 0); // Original (0b0 for copy)
+ const uint8_t pts_dts_indicator =
+ !pts.is_null() ? (!dts.is_null() ? 0x3u : 0x2u) : 0x0u;
+ dst[i++] = (pts_dts_indicator << 6) | // PTS DTS indicator
+ (0x0u << 5) | // ESCR flag
+ (0x0u << 4) | // ES rate flag
+ (0x0u << 3) | // DSM trick mode flag
+ (0x0u << 2) | // Additional copy info flag
+ (0x0u << 1) | // CRC flag
+ (0x0u << 0); // Extension flag
+ const size_t header_length_index = i++;
+ const size_t optional_header_base_end_index = i;
+ DCHECK_EQ(i, kOptionalHeaderBaseSize);
+
+ // Optional fields:
+ // PTS and DTS.
+ if (!pts.is_null()) {
+ i += FillInTimeStamp(&dst[i], pts_dts_indicator, pts);
+ if (!dts.is_null())
+ i += FillInTimeStamp(&dst[i], 0x1u, dts);
+ }
+
+ // Stuffing bytes (for unit data alignment).
+ const size_t remainder =
+ (kPacketHeaderBaseSize + i + unit_header_size) % kUnitDataAlignment;
+ if (remainder) {
+ const size_t n = kUnitDataAlignment - remainder;
+ std::memset(&dst[i], 0xFF, n);
+ i += n;
+ }
+
+ dst[header_length_index] = i - optional_header_base_end_index;
+ return i;
+}
+
+size_t FillInPacketHeader(uint8_t* dst,
+ uint8_t stream_id,
+ const base::TimeTicks& pts,
+ const base::TimeTicks& dts,
+ size_t unit_header_size,
+ size_t unit_size) {
+ // Reserve space for packet header base.
+ size_t i = kPacketHeaderBaseSize;
+ const size_t header_base_end_index = i;
+
+ // Fill in optional header.
+ i += FillInOptionalHeader(&dst[i], pts, dts, unit_header_size);
+
+ // Compute packet length.
+ size_t packet_length =
+ (i - header_base_end_index) + unit_header_size + unit_size;
+ if (packet_length >> 16) {
+ // The packet length is too large to be represented. That should only
+ // happen for video frames for which the packet length is not mandatory
+ // but may be set to 0, too.
+ DCHECK_GE(static_cast<unsigned>(stream_id),
+ WiFiDisplayElementaryStreamPacketizer::kFirstVideoStreamId);
+ DCHECK_LE(static_cast<unsigned>(stream_id),
+ WiFiDisplayElementaryStreamPacketizer::kLastVideoStreamId);
+ packet_length = 0u;
+ }
+
+ // Fill in packet header base.
+ size_t j = 0u;
+ dst[j++] = 0x00u; // Packet start code prefix (0x000001 in three bytes).
+ dst[j++] = 0x00u; //
+ dst[j++] = 0x01u; //
+ dst[j++] = stream_id;
+ dst[j++] = packet_length >> 8;
+ dst[j++] = packet_length & 0xFFu;
+ DCHECK_EQ(j, kPacketHeaderBaseSize);
+
+ return i;
+}
+
+} // namespace pes
+
+} // namespace
+
+WiFiDisplayElementaryStreamPacket::WiFiDisplayElementaryStreamPacket(
+ const HeaderBuffer& header_data,
+ size_t header_size,
+ const uint8_t* unit_header_data,
+ size_t unit_header_size,
+ const uint8_t* unit_data,
+ size_t unit_size)
+ : header_(header_buffer_, header_size),
+ unit_header_(unit_header_data, unit_header_size),
+ unit_(unit_data, unit_size) {
+ // Copy the actual header data bytes from the |header_data| argument to
+ // the |header_buffer_| member buffer used in the member initialization list.
+ std::memcpy(header_buffer_, header_data, header_.size());
+}
+
+WiFiDisplayElementaryStreamPacket::WiFiDisplayElementaryStreamPacket(
+ WiFiDisplayElementaryStreamPacket&& other)
+ : header_(header_buffer_, other.header().size()),
+ unit_header_(other.unit_header().data(), other.unit_header().size()),
+ unit_(other.unit().data(), other.unit().size()) {
+ // Copy the actual header data bytes from |other.header().data()| to
+ // the |header_buffer_| member buffer used in the member initialization list.
+ std::memcpy(header_buffer_, other.header().data(), header_.size());
+}
+
+// static
+WiFiDisplayElementaryStreamPacket
+WiFiDisplayElementaryStreamPacketizer::EncodeElementaryStreamUnit(
+ uint8_t stream_id,
+ const uint8_t* unit_header_data,
+ size_t unit_header_size,
+ const uint8_t* unit_data,
+ size_t unit_size,
+ const base::TimeTicks& pts,
+ const base::TimeTicks& dts) {
+ if (!unit_header_data) {
+ DCHECK_EQ(0u, unit_header_size);
+ unit_header_data = unit_data;
+ }
+
+ uint8_t header_data[pes::kPacketHeaderMaxSize];
+ size_t header_size = pes::FillInPacketHeader(header_data, stream_id, pts, dts,
+ unit_header_size, unit_size);
+ return WiFiDisplayElementaryStreamPacket(header_data, header_size,
+ unit_header_data, unit_header_size,
+ unit_data, unit_size);
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698