Move WV CAS Descriptor Generator to the media_cas_packager_sdk.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=219162536
This commit is contained in:
Fang Yu
2018-10-29 11:29:14 -07:00
parent 051a520776
commit cb773116a6
4 changed files with 443 additions and 0 deletions

View File

@@ -29,6 +29,7 @@ cc_binary(
name = "libmedia_cas_packager_sdk.so",
linkshared = 1,
deps = [
":wv_cas_ca_descriptor",
":wv_cas_ecm",
":wv_cas_status",
],
@@ -40,6 +41,7 @@ cc_library(
hdrs = glob(["*.h"]),
deps = [
"//base",
"@abseil_repo//absl/base:core_headers",
"//util:status",
"//media_cas_packager_sdk/internal:ecm",
"//media_cas_packager_sdk/internal:ecm_generator",
@@ -57,6 +59,34 @@ cc_binary(
],
)
cc_library(
name = "wv_cas_ca_descriptor",
srcs = ["wv_cas_ca_descriptor.cc"],
hdrs = ["wv_cas_ca_descriptor.h"],
copts = PUBLIC_COPTS,
deps = [
":wv_cas_status",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//util:status",
"//common:string_util",
"//protos/public:media_cas_proto",
],
)
cc_test(
name = "wv_cas_ca_descriptor_test",
size = "small",
srcs = ["wv_cas_ca_descriptor_test.cc"],
deps = [
":wv_cas_ca_descriptor",
":wv_cas_status",
"//testing:gunit_main",
"//protos/public:media_cas_proto",
],
)
cc_library(
name = "wv_cas_ecm",
srcs = ["wv_cas_ecm.cc"],

View File

@@ -0,0 +1,122 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "media_cas_packager_sdk/public/wv_cas_ca_descriptor.h"
#include <bitset>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "util/status.h"
#include "common/string_util.h"
#include "media_cas_packager_sdk/public/wv_cas_status.h"
#include "protos/public/media_cas.pb.h"
namespace widevine {
namespace cas {
namespace {
// Size of fixed portion of CA descriptor (before any private bytes).
static constexpr uint32_t kCaDescriptorBaseSize = 6;
// Size of fixed portion of CA descriptor that follows the length field.
// This and the size of any private bytes must be placed in the length field.
static constexpr uint32_t kCaDescriptorBasePostLengthSize = 4;
// Bitfield lengths for the CA descriptor fields
static constexpr int kNumBitsCaDescriptorTagField = 8;
static constexpr int kNumBitsCaDescriptorLengthField = 8;
static constexpr int kNumBitsCaSystemIdField = 16;
static constexpr int kNumBitsCaDescriptorReservedField = 3;
static constexpr int kNumBitsCaDescriptorPidField = 13;
// Bitfield constants for the CA descriptor fields.
// CA descriptor tag value, from table 2-45.
static constexpr uint32_t kCaDescriptorTag = 9;
// CA System ID for Widevine. From table in
// https://en.wikipedia.org/wiki/Conditional_access
static constexpr uint32_t kWidevineCaSystemId = 0x4AD4;
// Value for CA descriptor reserved field.
static constexpr uint32_t kUnusedZero = 0;
// The range of valid PIDs, from section 2.4.3.3, and table 2-3.
static constexpr uint32_t kMinValidPID = 0x0010;
static constexpr uint32_t kMaxValidPID = 0x1FFE;
} // namespace
WvCasStatus WvCasCaDescriptor::GenerateCaDescriptor(
uint16_t ca_pid, const std::string& provider, const std::string& content_id,
std::string* serialized_ca_desc) const {
if (serialized_ca_desc == nullptr) {
LOG(ERROR) << "Return CA descriptor std::string pointer is nullptr.";
return INVALID_ARGUMENT;
}
if (ca_pid < kMinValidPID || ca_pid > kMaxValidPID) {
LOG(ERROR) << "PID value is out of the valid range.";
return INVALID_ARGUMENT;
}
std::string private_data = "";
if (!provider.empty() && !content_id.empty()) {
private_data = GeneratePrivateData(provider, content_id);
}
const size_t descriptor_length =
kCaDescriptorBasePostLengthSize + private_data.size();
if (0xFF < descriptor_length) {
LOG(ERROR) << "Private data std::string is too large.";
return INVALID_ARGUMENT;
}
std::bitset<kNumBitsCaDescriptorTagField> tag(kCaDescriptorTag);
// Length field: insert count of bytes that follow this field,
// including private bytes.
std::bitset<kNumBitsCaDescriptorLengthField> length(descriptor_length);
std::bitset<kNumBitsCaSystemIdField> ca_system_id(kWidevineCaSystemId);
std::bitset<kNumBitsCaDescriptorReservedField> reserved(kUnusedZero);
std::bitset<kNumBitsCaDescriptorPidField> pid(ca_pid);
// Converts bitset to a std::string where each char represents a bit.
std::string descriptor_bitset = absl::StrCat(
tag.to_string(), length.to_string(), ca_system_id.to_string(),
reserved.to_string(), pid.to_string());
if (descriptor_bitset.size() != kCaDescriptorBaseSize * 8) {
LOG(ERROR) << "Error creating CA descriptor.";
return INTERNAL;
}
std::string descriptor;
util::Status status =
string_util::BitsetStringToBinaryString(descriptor_bitset, &descriptor);
*serialized_ca_desc = descriptor;
if (!private_data.empty()) {
*serialized_ca_desc += private_data;
}
return OK;
}
size_t WvCasCaDescriptor::CaDescriptorBaseSize() const {
return kCaDescriptorBaseSize;
}
std::string WvCasCaDescriptor::GeneratePrivateData(const std::string& provider,
const std::string& content_id) const {
CaDescriptorPrivateData private_data;
private_data.set_provider(provider);
private_data.set_content_id(content_id);
return private_data.SerializeAsString();
}
} // namespace cas
} // namespace widevine

View File

@@ -0,0 +1,75 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CA_DESCRIPTOR_H_
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CA_DESCRIPTOR_H_
#include <stddef.h>
#include <string>
#include "media_cas_packager_sdk/public/wv_cas_status.h"
namespace widevine {
namespace cas {
// Simple CA Descriptor generator for Widevine CAS.
//
// The CA descriptor format is defined in ISO/IEC 13818-1:2015 (table 2-59):
// CA_descriptor() {
// descriptor_tag 8 uimsbf
// descriptor_length 8 uimsbf
// CA_system_id 16 uimsbf
// reserved 3 bslbf
// CA_PID 13 uimsbf
// for (i = 0; i < N; i++) {
// private_data_byte uimsbf
// }
// }
//
// Class is not thread safe.
class WvCasCaDescriptor {
public:
WvCasCaDescriptor() = default;
WvCasCaDescriptor(const WvCasCaDescriptor&) = delete;
WvCasCaDescriptor& operator=(const WvCasCaDescriptor&) = delete;
virtual ~WvCasCaDescriptor() = default;
// Generate a CA descriptor for the ECM stream for an encrypted program
// stream.
//
// Args:
// |ca_pid| the 13-bit PID of the ECMs
// |provider| provider name, put in private data for client to construct pssh
// |content_id| content ID, put in private data for client to construct pssh
// |serialized_ca_desc| a std::string object to receive the encoded descriptor.
//
// Notes:
// The descriptor generated by this call may be inserted into a CA Table
// section (for an EMM stream) or into a TS Program Map Table section (for an
// ECM stream). The descriptor will be 6 bytes plus any bytes added as
// (user-defined) private data.
virtual WvCasStatus GenerateCaDescriptor(uint16_t ca_pid,
const std::string& provider,
const std::string& content_id,
std::string* serialized_ca_desc) const;
// Return the base size (before private data is added) of the CA
// descriptor. The user can call this to plan the layout of the Table section
// where the descriptor will be added.
virtual size_t CaDescriptorBaseSize() const;
protected:
// Protected visibility to support unit testing.
virtual std::string GeneratePrivateData(const std::string& provider,
const std::string& content_id) const;
};
} // namespace cas
} // namespace widevine
#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CA_DESCRIPTOR_H_

View File

@@ -0,0 +1,216 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "media_cas_packager_sdk/public/wv_cas_ca_descriptor.h"
#include <string>
#include "testing/gunit.h"
#include "media_cas_packager_sdk/public/wv_cas_status.h"
#include "protos/public/media_cas.pb.h"
using ::testing::Test;
namespace widevine {
namespace cas {
namespace {
// Random value for PID
static constexpr int kTestPid = 50;
static constexpr char kProvider[] = "widevine_test";
static constexpr char kContentId[] = "1234";
} // namespace
class WvCasCaDescriptorTest : public Test {
protected:
WvCasCaDescriptorTest() {}
WvCasCaDescriptor ca_descriptor_;
std::string actual_ca_descriptor_;
};
TEST_F(WvCasCaDescriptorTest, BaseSize) {
EXPECT_EQ(6, ca_descriptor_.CaDescriptorBaseSize());
}
TEST_F(WvCasCaDescriptorTest, BasicGoodGen) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, NoReturnStringFail) {
EXPECT_EQ(INVALID_ARGUMENT,
ca_descriptor_.GenerateCaDescriptor(kTestPid, "", "", nullptr));
}
TEST_F(WvCasCaDescriptorTest, PidTooLowFail) {
const uint32_t bad_pid = 0x10 - 1;
EXPECT_EQ(INVALID_ARGUMENT, ca_descriptor_.GenerateCaDescriptor(
bad_pid, "", "", &actual_ca_descriptor_));
}
TEST_F(WvCasCaDescriptorTest, PidMinOK) {
const uint32_t min_pid = 0x10;
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(min_pid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x10", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidMaxOK) {
const uint32_t max_pid = 0x1FFE;
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(max_pid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x1f\xfe");
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTooHighFail) {
const uint32_t bad_pid = 0x1FFF;
EXPECT_EQ(INVALID_ARGUMENT, ca_descriptor_.GenerateCaDescriptor(
bad_pid, "", "", &actual_ca_descriptor_));
}
TEST_F(WvCasCaDescriptorTest, PidOneByte) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(255, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\xff", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidSecondByte) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x1F00, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x1f\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTwelveBits) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0xFFF, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x0f\xff");
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidThirteenthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x1000, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x10\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTwelthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x800, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x08\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidElevenththBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x400, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x04\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTenthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x200, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x02\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidNinthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x100, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x01\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataOnlyProviderIgnored) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, kProvider, "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataOnlyContentIdIgnored) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, "", kContentId,
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateData) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x19\x4a\xd4\x00\x32", 6);
CaDescriptorPrivateData private_data;
private_data.set_provider(kProvider);
private_data.set_content_id(kContentId);
EXPECT_EQ(expected_ca_descriptor + private_data.SerializeAsString(),
actual_ca_descriptor_);
}
class FakePrivateDataCaDescriptor : public WvCasCaDescriptor {
public:
void set_private_data(std::string private_data) { private_data_ = private_data; }
protected:
std::string GeneratePrivateData(const std::string& provider,
const std::string& content_id) const override {
return private_data_;
}
private:
std::string private_data_;
};
TEST_F(WvCasCaDescriptorTest, PrivateDataOneByte) {
FakePrivateDataCaDescriptor fake_descriptor;
fake_descriptor.set_private_data("X");
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x05\x4a\xd4\x00\x32X", 7);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataMultipleBytes) {
const std::string private_data_bytes("X1234abcde");
FakePrivateDataCaDescriptor fake_descriptor;
fake_descriptor.set_private_data(private_data_bytes);
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x0e\x4a\xd4\x00\x32", 6);
EXPECT_EQ(expected_ca_descriptor + private_data_bytes, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataMaxNumberBytes) {
const std::string private_data_bytes(251, 'x');
FakePrivateDataCaDescriptor fake_descriptor;
fake_descriptor.set_private_data(private_data_bytes);
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\xff\x4a\xd4\x00\x32", 6);
EXPECT_EQ(expected_ca_descriptor + private_data_bytes, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataTooManyBytesFail) {
const std::string private_data_bytes(252, 'X');
FakePrivateDataCaDescriptor fake_descriptor;
fake_descriptor.set_private_data(private_data_bytes);
EXPECT_EQ(INVALID_ARGUMENT,
fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
}
} // namespace cas
} // namespace widevine