7 #include "packager/media/crypto/subsample_generator.h"
12 #include "packager/media/base/decrypt_config.h"
13 #include "packager/media/base/video_stream_info.h"
14 #include "packager/media/codecs/av1_parser.h"
15 #include "packager/media/codecs/video_slice_header_parser.h"
16 #include "packager/media/codecs/vp8_parser.h"
17 #include "packager/media/codecs/vp9_parser.h"
23 const size_t kAesBlockSize = 16u;
25 uint8_t GetNaluLengthSize(
const StreamInfo& stream_info) {
26 if (stream_info.stream_type() != kStreamVideo)
29 const VideoStreamInfo& video_stream_info =
30 static_cast<const VideoStreamInfo&
>(stream_info);
31 return video_stream_info.nalu_length_size();
34 bool ShouldAlignProtectedData(Codec codec,
35 FourCC protection_scheme,
36 bool vp9_subsample_encryption) {
48 return vp9_subsample_encryption;
58 return protection_scheme == FOURCC_cbc1 ||
59 protection_scheme == FOURCC_cens ||
60 protection_scheme == FOURCC_cenc;
67 class SubsampleOrganizer {
69 SubsampleOrganizer(
bool align_protected_data,
70 std::vector<SubsampleEntry>* subsamples)
71 : align_protected_data_(align_protected_data), subsamples_(subsamples) {}
73 ~SubsampleOrganizer() {
74 if (accumulated_clear_bytes_ > 0) {
75 PushSubsample(accumulated_clear_bytes_, 0);
76 accumulated_clear_bytes_ = 0;
80 void AddSubsample(
size_t clear_bytes,
size_t cipher_bytes) {
81 DCHECK_LT(clear_bytes, std::numeric_limits<uint32_t>::max());
82 DCHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
84 if (align_protected_data_ && cipher_bytes != 0) {
85 const size_t misalign_bytes = cipher_bytes % kAesBlockSize;
86 clear_bytes += misalign_bytes;
87 cipher_bytes -= misalign_bytes;
90 accumulated_clear_bytes_ += clear_bytes;
92 if (cipher_bytes == 0)
95 PushSubsample(accumulated_clear_bytes_, cipher_bytes);
96 accumulated_clear_bytes_ = 0;
100 SubsampleOrganizer(
const SubsampleOrganizer&) =
delete;
101 SubsampleOrganizer& operator=(
const SubsampleOrganizer&) =
delete;
103 void PushSubsample(
size_t clear_bytes,
size_t cipher_bytes) {
104 const uint16_t kUInt16Max = std::numeric_limits<uint16_t>::max();
105 while (clear_bytes > kUInt16Max) {
106 subsamples_->emplace_back(kUInt16Max, 0);
107 clear_bytes -= kUInt16Max;
109 subsamples_->emplace_back(
static_cast<uint16_t
>(clear_bytes),
110 static_cast<uint32_t
>(cipher_bytes));
113 const bool align_protected_data_ =
false;
114 std::vector<SubsampleEntry>*
const subsamples_ =
nullptr;
115 size_t accumulated_clear_bytes_ = 0;
121 : vp9_subsample_encryption_(vp9_subsample_encryption) {}
123 SubsampleGenerator::~SubsampleGenerator() {}
127 codec_ = stream_info.codec();
128 nalu_length_size_ = GetNaluLengthSize(stream_info);
135 if (vp9_subsample_encryption_)
142 case kCodecH265DolbyVision:
147 if (nalu_length_size_ > 0) {
148 LOG(WARNING) <<
"Unknown video codec '" << codec_ <<
"'";
149 return Status(error::ENCRYPTION_FAILURE,
"Unknown video codec.");
155 const size_t kConfigOBUsOffset = 4;
156 const bool has_config_obus =
157 stream_info.codec_config().size() > kConfigOBUsOffset;
158 std::vector<AV1Parser::Tile> tiles;
159 if (has_config_obus &&
161 &stream_info.codec_config()[kConfigOBUsOffset],
162 stream_info.codec_config().size() - kConfigOBUsOffset, &tiles)) {
164 error::ENCRYPTION_FAILURE,
165 "Failed to parse configOBUs in AV1CodecConfigurationRecord.");
167 DCHECK(tiles.empty());
169 if (header_parser_) {
170 CHECK_NE(nalu_length_size_, 0u) <<
"AnnexB stream is not supported yet";
171 if (!header_parser_->Initialize(stream_info.codec_config())) {
172 return Status(error::ENCRYPTION_FAILURE,
173 "Failed to read SPS and PPS data.");
177 align_protected_data_ = ShouldAlignProtectedData(codec_, protection_scheme,
178 vp9_subsample_encryption_);
180 if (protection_scheme == kAppleSampleAesProtectionScheme) {
181 const size_t kH264LeadingClearBytesSize = 32u;
182 const size_t kAudioLeadingClearBytesSize = 16u;
185 leading_clear_bytes_size_ = kH264LeadingClearBytesSize;
186 min_protected_data_size_ =
187 leading_clear_bytes_size_ + kAesBlockSize + 1u;
190 FALLTHROUGH_INTENDED;
192 leading_clear_bytes_size_ = kAudioLeadingClearBytesSize;
193 min_protected_data_size_ = leading_clear_bytes_size_ + kAesBlockSize;
198 leading_clear_bytes_size_ = 0;
199 min_protected_data_size_ = leading_clear_bytes_size_ + kAesBlockSize;
202 LOG(ERROR) <<
"Unexpected codec for SAMPLE-AES " << codec_;
203 return Status(error::ENCRYPTION_FAILURE,
204 "Unexpected codec for SAMPLE-AES.");
211 const uint8_t* frame,
213 std::vector<SubsampleEntry>* subsamples) {
217 return GenerateSubsamplesFromAV1Frame(frame, frame_size, subsamples);
219 FALLTHROUGH_INTENDED;
221 case kCodecH265DolbyVision:
222 return GenerateSubsamplesFromH26xFrame(frame, frame_size, subsamples);
224 if (vp9_subsample_encryption_)
225 return GenerateSubsamplesFromVPxFrame(frame, frame_size, subsamples);
231 if (leading_clear_bytes_size_ > 0) {
232 SubsampleOrganizer subsample_organizer(align_protected_data_,
234 const size_t clear_bytes =
235 std::min(frame_size, leading_clear_bytes_size_);
236 const size_t cipher_bytes = frame_size - clear_bytes;
237 subsample_organizer.AddSubsample(clear_bytes, cipher_bytes);
246 void SubsampleGenerator::InjectVpxParserForTesting(
247 std::unique_ptr<VPxParser> vpx_parser) {
248 vpx_parser_ = std::move(vpx_parser);
251 void SubsampleGenerator::InjectVideoSliceHeaderParserForTesting(
252 std::unique_ptr<VideoSliceHeaderParser> header_parser) {
253 header_parser_ = std::move(header_parser);
256 void SubsampleGenerator::InjectAV1ParserForTesting(
257 std::unique_ptr<AV1Parser> av1_parser) {
258 av1_parser_ = std::move(av1_parser);
261 Status SubsampleGenerator::GenerateSubsamplesFromVPxFrame(
262 const uint8_t* frame,
264 std::vector<SubsampleEntry>* subsamples) {
266 std::vector<VPxFrameInfo> vpx_frames;
267 if (!vpx_parser_->Parse(frame, frame_size, &vpx_frames))
268 return Status(error::ENCRYPTION_FAILURE,
"Failed to parse vpx frame.");
270 SubsampleOrganizer subsample_organizer(align_protected_data_, subsamples);
272 size_t total_size = 0;
273 for (
const VPxFrameInfo& frame : vpx_frames) {
274 subsample_organizer.AddSubsample(
275 frame.uncompressed_header_size,
276 frame.frame_size - frame.uncompressed_header_size);
277 total_size += frame.frame_size;
280 const bool is_superframe = vpx_frames.size() > 1;
282 const size_t index_size = frame_size - total_size;
283 DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
284 DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
285 subsample_organizer.AddSubsample(index_size, 0);
287 DCHECK_EQ(total_size, frame_size);
292 Status SubsampleGenerator::GenerateSubsamplesFromH26xFrame(
293 const uint8_t* frame,
295 std::vector<SubsampleEntry>* subsamples) {
296 DCHECK_NE(nalu_length_size_, 0u);
297 DCHECK(header_parser_);
299 SubsampleOrganizer subsample_organizer(align_protected_data_, subsamples);
301 const Nalu::CodecType nalu_type =
302 (codec_ == kCodecH265 || codec_ == kCodecH265DolbyVision) ? Nalu::kH265
304 NaluReader reader(nalu_type, nalu_length_size_, frame, frame_size);
307 NaluReader::Result result;
308 while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
311 if (leading_clear_bytes_size_ == 0 && !header_parser_->ProcessNalu(nalu)) {
312 LOG(ERROR) <<
"Failed to process NAL unit: NAL type = " << nalu.type();
313 return Status(error::ENCRYPTION_FAILURE,
"Failed to process NAL unit.");
316 const size_t nalu_total_size = nalu.header_size() + nalu.payload_size();
317 size_t clear_bytes = 0;
318 if (nalu.is_video_slice() && nalu_total_size >= min_protected_data_size_) {
319 clear_bytes = leading_clear_bytes_size_;
320 if (clear_bytes == 0) {
323 const int64_t video_slice_header_size =
324 header_parser_->GetHeaderSize(nalu);
325 if (video_slice_header_size < 0) {
326 LOG(ERROR) <<
"Failed to read slice header.";
327 return Status(error::ENCRYPTION_FAILURE,
328 "Failed to read slice header.");
330 clear_bytes = nalu.header_size() + video_slice_header_size;
334 clear_bytes = nalu_total_size;
336 const size_t cipher_bytes = nalu_total_size - clear_bytes;
337 subsample_organizer.AddSubsample(nalu_length_size_ + clear_bytes,
340 if (result != NaluReader::kEOStream) {
341 LOG(ERROR) <<
"Failed to parse NAL units.";
342 return Status(error::ENCRYPTION_FAILURE,
"Failed to parse NAL units.");
347 Status SubsampleGenerator::GenerateSubsamplesFromAV1Frame(
348 const uint8_t* frame,
350 std::vector<SubsampleEntry>* subsamples) {
352 std::vector<AV1Parser::Tile> av1_tiles;
353 if (!av1_parser_->Parse(frame, frame_size, &av1_tiles))
354 return Status(error::ENCRYPTION_FAILURE,
"Failed to parse AV1 frame.");
356 SubsampleOrganizer subsample_organizer(align_protected_data_, subsamples);
358 size_t last_tile_end_offset = 0;
359 for (
const AV1Parser::Tile& tile : av1_tiles) {
360 DCHECK_LE(last_tile_end_offset, tile.start_offset_in_bytes);
363 subsample_organizer.AddSubsample(
364 tile.start_offset_in_bytes - last_tile_end_offset, tile.size_in_bytes);
365 last_tile_end_offset = tile.start_offset_in_bytes + tile.size_in_bytes;
367 DCHECK_LE(last_tile_end_offset, frame_size);
368 if (last_tile_end_offset < frame_size)
369 subsample_organizer.AddSubsample(frame_size - last_tile_end_offset, 0);
All the methods that are virtual are virtual for mocking.