blob: 075ea59ecce97c28ca5af576d65f678ca50833f2 [file] [log] [blame]
// Copyright 2015 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 "media/formats/mp2t/descriptors.h"
#include <vector>
#include "base/check.h"
#include "media/base/bit_reader.h"
#include "media/base/encryption_pattern.h"
#include "media/formats/mp2t/mp2t_common.h"
namespace media {
namespace mp2t {
namespace {
// Tag values for various kinds of descriptors for which there is specific
// parsing support herein.
enum DescriptorTag {
DESCRIPTOR_TAG_REGISTRATION = 5,
DESCRIPTOR_TAG_CA = 9,
DESCRIPTOR_TAG_PRIVATE_DATA_INDICATOR = 15,
};
const int kCASystemIdCenc = 0x6365; // 'ce'
const uint32_t kFourccCbcs = 0x63626373; // 'cbcs'
class StringBitReader : public BitReader {
public:
StringBitReader(const std::string& input);
~StringBitReader() override;
};
StringBitReader::StringBitReader(const std::string& input)
: BitReader(reinterpret_cast<const uint8_t*>(input.data()), input.size()) {}
StringBitReader::~StringBitReader() {}
} // namespace
Descriptors::Descriptors() {}
Descriptors::Descriptors(const Descriptors& other) = default;
Descriptors::~Descriptors() {}
bool Descriptors::Read(BitReader* reader, int size) {
DCHECK(reader);
DCHECK(size >= 0);
descriptors_.clear();
if (size == 0)
return true;
int initial_bits_read = reader->bits_read();
int bits_read = 0;
int bits_available = reader->bits_available();
int size_in_bits = 8 * size;
if (size_in_bits > bits_available)
return false;
bits_available = size_in_bits;
do {
int tag;
size_t length;
RCHECK(reader->ReadBits(8, &tag));
RCHECK(reader->ReadBits(8, &length));
char data[256];
for (size_t i = 0; i < length; i++) {
RCHECK(reader->ReadBits(8, &data[i]));
}
descriptors_.insert(Descriptor(tag, std::string(data, length)));
bits_read = reader->bits_read() - initial_bits_read;
} while (bits_read < bits_available);
return bits_read == bits_available;
}
bool Descriptors::HasRegistrationDescriptor(
int64_t* format_identifier,
std::string* additional_info) const {
DCHECK(format_identifier);
DCHECK(additional_info);
auto search = descriptors_.find(DESCRIPTOR_TAG_REGISTRATION);
if (search == descriptors_.end())
return false;
const std::string& data = search->second;
StringBitReader reader(data);
RCHECK(reader.ReadBits(32, format_identifier));
size_t extra_bits = reader.bits_available();
RCHECK(extra_bits % 8 == 0);
RCHECK(extra_bits > 0);
RCHECK(reader.ReadString(extra_bits, additional_info));
return true;
}
bool Descriptors::HasCADescriptor(int* system_id,
int* pid,
std::string* private_data) const {
DCHECK(system_id);
DCHECK(pid);
DCHECK(private_data);
auto search = descriptors_.find(DESCRIPTOR_TAG_CA);
if (search == descriptors_.end())
return false;
const std::string& data = search->second;
StringBitReader reader(data);
RCHECK(reader.ReadBits(16, system_id));
RCHECK(reader.SkipBits(3));
RCHECK(reader.ReadBits(13, pid));
size_t extra_bits = reader.bits_available();
RCHECK(extra_bits % 8 == 0);
RCHECK(reader.ReadString(extra_bits, private_data));
return true;
}
bool Descriptors::HasCADescriptorCenc(int* ca_pid,
int* pssh_pid,
EncryptionScheme* scheme) const {
DCHECK(ca_pid);
DCHECK(pssh_pid);
int system_id;
std::string private_data;
if (!HasCADescriptor(&system_id, ca_pid, &private_data))
return false;
if (system_id != kCASystemIdCenc)
return false;
StringBitReader reader(private_data);
uint32_t scheme_type;
uint32_t scheme_version;
int num_systems;
int encryption_algorithm;
char pssh_system_id[16];
// TODO(dougsteed). Currently we don't check many of the following values,
// and we only support the 'cbcs' scheme (which involves AES-CBC encryption).
// When we flesh out this implementation to cover all of ISO/IEC 23001-9 we
// will need to use and check these values more comprehensively.
RCHECK(reader.ReadBits(32, &scheme_type));
RCHECK(scheme_type == kFourccCbcs);
RCHECK(reader.ReadBits(32, &scheme_version));
RCHECK(reader.ReadBits(8, &num_systems));
RCHECK(num_systems == 1);
RCHECK(reader.ReadBits(24, &encryption_algorithm));
for (size_t i = 0; i < 16; i++) {
RCHECK(reader.ReadBits(8, &pssh_system_id[i]));
}
RCHECK(reader.ReadBits(13, pssh_pid));
// The pattern is actually set differently for audio and video, so OK not to
// set it here. Important thing is to set the cipher mode.
*scheme = EncryptionScheme::kCbcs;
return true;
}
bool Descriptors::HasPrivateDataIndicator(int64_t value) const {
int64_t private_data_indicator;
auto search = descriptors_.find(DESCRIPTOR_TAG_PRIVATE_DATA_INDICATOR);
if (search == descriptors_.end())
return false;
const std::string& data = search->second;
StringBitReader reader(data);
RCHECK(reader.ReadBits(32, &private_data_indicator));
RCHECK(reader.bits_available() == 0);
return private_data_indicator == value;
}
} // namespace mp2t
} // namespace media