summaryrefslogtreecommitdiffstats
path: root/media/cdm/cenc_utils.cc
blob: 1e33cca361337898f0371281632af05e8b7d0759 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 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/cdm/cenc_utils.h"

#include "base/stl_util.h"
#include "media/formats/mp4/box_definitions.h"
#include "media/formats/mp4/box_reader.h"

namespace media {

// The initialization data for encrypted media files using the ISO Common
// Encryption ('cenc') protection scheme may contain one or more protection
// system specific header ('pssh') boxes.
// ref: https://w3c.github.io/encrypted-media/cenc-format.html

// SystemID for the Common System.
// https://w3c.github.io/encrypted-media/cenc-format.html#common-system
const uint8_t kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec,
                                    0xc0, 0xb2, 0x4d, 0x02,
                                    0xac, 0xe3, 0x3c, 0x1e,
                                    0x52, 0xe2, 0xfb, 0x4b };

static bool ReadAllPsshBoxes(
    const std::vector<uint8_t>& input,
    std::vector<mp4::FullProtectionSystemSpecificHeader>* pssh_boxes) {
  DCHECK(!input.empty());

  // Verify that |input| contains only 'pssh' boxes. ReadAllChildren() is
  // templated, so it checks that each box in |input| matches the box type of
  // the parameter (in this case mp4::ProtectionSystemSpecificHeader is a
  // 'pssh' box). mp4::ProtectionSystemSpecificHeader doesn't validate the
  // 'pssh' contents, so this simply verifies that |input| only contains
  // 'pssh' boxes and nothing else.
  scoped_ptr<mp4::BoxReader> input_reader(
      mp4::BoxReader::ReadConcatentatedBoxes(
          vector_as_array(&input), input.size()));
  std::vector<mp4::ProtectionSystemSpecificHeader> raw_pssh_boxes;
  if (!input_reader->ReadAllChildren(&raw_pssh_boxes))
    return false;

  // Now that we have |input| parsed into |raw_pssh_boxes|, reparse each one
  // into a mp4::FullProtectionSystemSpecificHeader, which extracts all the
  // relevant fields from the box. Since there may be unparseable 'pssh' boxes
  // (due to unsupported version, for example), this is done one by one,
  // ignoring any boxes that can't be parsed.
  for (const auto& raw_pssh_box : raw_pssh_boxes) {
    scoped_ptr<mp4::BoxReader> raw_pssh_reader(
        mp4::BoxReader::ReadConcatentatedBoxes(
            vector_as_array(&raw_pssh_box.raw_box),
            raw_pssh_box.raw_box.size()));
    // ReadAllChildren() appends any successfully parsed box onto it's
    // parameter, so |pssh_boxes| will contain the collection of successfully
    // parsed 'pssh' boxes. If an error occurs, try the next box.
    if (!raw_pssh_reader->ReadAllChildren(pssh_boxes))
      continue;
  }

  // Must have successfully parsed at least one 'pssh' box.
  return pssh_boxes->size() > 0;
}

bool ValidatePsshInput(const std::vector<uint8_t>& input) {
  // No 'pssh' boxes is considered valid.
  if (input.empty())
    return true;

  std::vector<mp4::FullProtectionSystemSpecificHeader> children;
  return ReadAllPsshBoxes(input, &children);
}

bool GetKeyIdsForCommonSystemId(const std::vector<uint8_t>& input,
                                KeyIdList* key_ids) {
  KeyIdList result;
  std::vector<uint8_t> common_system_id(
      kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));

  if (!input.empty()) {
    std::vector<mp4::FullProtectionSystemSpecificHeader> children;
    if (!ReadAllPsshBoxes(input, &children))
      return false;

    // Check all children for an appropriate 'pssh' box, concatenating any
    // key IDs found.
    for (const auto& child : children) {
      if (child.system_id == common_system_id && child.key_ids.size() > 0)
        result.insert(result.end(), child.key_ids.begin(), child.key_ids.end());
    }
  }

  key_ids->swap(result);
  return key_ids->size() > 0;
}

bool GetPsshData(const std::vector<uint8_t>& input,
                 const std::vector<uint8_t>& system_id,
                 std::vector<uint8_t>* pssh_data) {
  if (input.empty())
    return false;

  std::vector<mp4::FullProtectionSystemSpecificHeader> children;
  if (!ReadAllPsshBoxes(input, &children))
    return false;

  // Check all children for an appropriate 'pssh' box, returning |data| from
  // the first one found.
  for (const auto& child : children) {
    if (child.system_id == system_id) {
      pssh_data->assign(child.data.begin(), child.data.end());
      return true;
    }
  }

  // No matching 'pssh' box found.
  return false;
}

}  // namespace media