| 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
|
|
|