chromium/media/formats/mp2t/ts_section_cets_ecm.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/formats/mp2t/ts_section_cets_ecm.h"

#include "base/check.h"
#include "media/base/bit_reader.h"
#include "media/formats/mp2t/mp2t_common.h"

namespace media {
namespace mp2t {

TsSectionCetsEcm::TsSectionCetsEcm(
    const RegisterNewKeyIdAndIvCB& register_new_key_id_and_iv_cb)
    : register_new_key_id_and_iv_cb_(register_new_key_id_and_iv_cb) {}

TsSectionCetsEcm::~TsSectionCetsEcm() {}

bool TsSectionCetsEcm::Parse(bool payload_unit_start_indicator,
                             base::span<const uint8_t> buf) {
  BitReader bit_reader(buf.data(), buf.size());
  int num_states;
  bool next_key_id_flag;
  bool no_byte_align;
  int iv_size;
  std::string key_id;
  int transport_scrambling_control;
  int num_au;
  bool key_id_flag;
  int au_byte_offset_size;
  std::string iv;
  // TODO(dougsteed). Currently we allow only a subset of the possible values.
  // When we flesh out this implementation to cover all of ISO/IEC 23001-9 we
  // will need to generalize this.
  RCHECK(bit_reader.ReadBits(2, &num_states));
  RCHECK(num_states == 1);
  RCHECK(bit_reader.ReadFlag(&next_key_id_flag) && !next_key_id_flag);
  // TODO(dougsteed). The standard (ISO/IEC 23001-9:2014) reserves 3 bits,
  // whereas it likely was intended to be 5 bits to follow the usual practice of
  // syncing to a byte boundary for the byte oriented fields that follow.
  // For now, we plan to use it with byte alignment for convenience. Rather than
  // just having an unadvertized deviation from the standard, I have repurposed
  // the first reserved bit as a flag. This approach gives flexibility for the
  // future if the standard is fixed or comes into wide use in its present form.
  RCHECK(bit_reader.ReadFlag(&no_byte_align));
  if (no_byte_align)
    RCHECK(bit_reader.SkipBits(2));
  else
    RCHECK(bit_reader.SkipBits(4));
  RCHECK(bit_reader.ReadBits(8, &iv_size));
  RCHECK(iv_size == 16);
  RCHECK(bit_reader.ReadString(128, &key_id));
  RCHECK(bit_reader.ReadBits(2, &transport_scrambling_control));
  RCHECK(transport_scrambling_control == 0);
  RCHECK(bit_reader.ReadBits(6, &num_au));
  RCHECK(num_au == 1);
  RCHECK(bit_reader.ReadFlag(&key_id_flag) && !key_id_flag);
  RCHECK(bit_reader.SkipBits(3));
  RCHECK(bit_reader.ReadBits(4, &au_byte_offset_size));
  RCHECK(au_byte_offset_size == 0);
  RCHECK(bit_reader.ReadString(128, &iv));
  // The CETS-ECM is supposed to  use adaptation field stuffing to fill the TS
  // packet, so there should be no data left to read.
  RCHECK(bit_reader.bits_available() == 0);
  register_new_key_id_and_iv_cb_.Run(key_id, iv);
  return true;
}

void TsSectionCetsEcm::Flush() {
  // No pending state.
}

void TsSectionCetsEcm::Reset() {
  // No state to clean up.
}

}  // namespace mp2t
}  // namespace media