Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: media/formats/mp2t/es_parser_h264.cc

Issue 1517473002: Support HLS MPEG2 TS with SAMPLE-AES encryption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@encryption_scheme
Patch Set: rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/formats/mp2t/es_parser_h264.h ('k') | media/formats/mp2t/mp2t_stream_parser.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/formats/mp2t/es_parser_h264.h" 5 #include "media/formats/mp2t/es_parser_h264.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h" 10 #include "base/numerics/safe_conversions.h"
11 #include "base/optional.h" 11 #include "base/optional.h"
12 #include "media/base/decrypt_config.h"
12 #include "media/base/encryption_scheme.h" 13 #include "media/base/encryption_scheme.h"
13 #include "media/base/media_util.h" 14 #include "media/base/media_util.h"
14 #include "media/base/stream_parser_buffer.h" 15 #include "media/base/stream_parser_buffer.h"
15 #include "media/base/timestamp_constants.h" 16 #include "media/base/timestamp_constants.h"
16 #include "media/base/video_frame.h" 17 #include "media/base/video_frame.h"
17 #include "media/filters/h264_parser.h" 18 #include "media/filters/h264_parser.h"
18 #include "media/formats/common/offset_byte_queue.h" 19 #include "media/formats/common/offset_byte_queue.h"
19 #include "media/formats/mp2t/mp2t_common.h" 20 #include "media/formats/mp2t/mp2t_common.h"
20 #include "ui/gfx/geometry/rect.h" 21 #include "ui/gfx/geometry/rect.h"
21 #include "ui/gfx/geometry/size.h" 22 #include "ui/gfx/geometry/size.h"
22 23
23 namespace media { 24 namespace media {
24 namespace mp2t { 25 namespace mp2t {
25 26
27 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
28 namespace {
29
30 const int kSampleAESMaxUnprotectedNALULength = 48;
31 const int kSampleAESClearLeaderSize = 32;
32 const int kSampleAESEncryptBlocks = 1;
33 const int kSampleAESSkipBlocks = 9;
34 const int kSampleAESPatternUnit =
35 (kSampleAESEncryptBlocks + kSampleAESSkipBlocks) * 16;
36
37 // Attempts to find the first or only EP3B (emulation prevention 3 byte) in
38 // the part of the |buffer| between |start_pos| and |end_pos|. Returns the
39 // position of the EP3B, or 0 if there are none.
40 // Note: the EP3B always follows two zero bytes, so the value 0 can never be a
41 // valid position.
42 int FindEP3B(const uint8_t* buffer, int start_pos, int end_pos) {
43 const uint8_t* data = buffer + start_pos;
44 int data_size = end_pos - start_pos;
45 DCHECK_GE(data_size, 0);
46 int bytes_left = data_size;
47
48 while (bytes_left >= 4) {
49 if (data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x03 &&
50 data[3] <= 0x03) {
51 return (data - buffer) + 2;
52 }
53 ++data;
54 --bytes_left;
55 }
56 return 0;
57 }
58
59 // Remove the byte at |pos| in the |buffer| and close up the gap, moving all the
60 // bytes from [pos + 1, end_pos) to [pos, end_pos - 1).
61 void RemoveByte(uint8_t* buffer, int pos, int end_pos) {
62 memmove(&buffer[pos], &buffer[pos + 1], end_pos - pos - 1);
63 }
64
65 // Given an Access Unit pointed to by |au| of size |au_size|, removes emulation
66 // prevention 3 bytes (EP3B) from within the |protected_blocks|. Also computes
67 // the |subsamples| vector describing the resulting AU.
68 // Returns the allocated buffer holding the adjusted copy, or NULL if no size
69 // adjustment was necessary.
70 std::unique_ptr<uint8_t[]> AdjustAUForSampleAES(
71 const uint8_t* au,
72 int* au_size,
73 const Ranges<int>& protected_blocks,
74 std::vector<SubsampleEntry>* subsamples) {
75 DCHECK(subsamples);
76 DCHECK(au_size);
77 std::unique_ptr<uint8_t[]> result;
78 int& au_end_pos = *au_size;
79
80 // 1. Considering each protected block in turn, find any emulation prevention
81 // 3 bytes (EP3B) within it, keeping track of their positions. While doing so,
82 // produce a revised Ranges<int> reflecting the new protected block positions
83 // that will apply after we have removed the EP3Bs.
84 Ranges<int> adjusted_protected_blocks;
85 std::vector<int> epbs;
86 int adjustment = 0;
87 for (size_t i = 0; i < protected_blocks.size(); i++) {
88 int start_pos = protected_blocks.start(i);
89 int end_pos = protected_blocks.end(i);
90 int search_pos = start_pos;
91 int epb_pos;
92 int block_adjustment = 0;
93 while ((epb_pos = FindEP3B(au, search_pos, end_pos))) {
94 epbs.push_back(epb_pos);
95 block_adjustment++;
96 search_pos = epb_pos + 2;
97 }
98 // adjust the start_pos and end_pos to accommodate the EPBs that will be
99 // removed.
100 start_pos -= adjustment;
101 adjustment += block_adjustment;
102 end_pos -= adjustment;
103 if (end_pos - start_pos > kSampleAESMaxUnprotectedNALULength)
104 adjusted_protected_blocks.Add(start_pos, end_pos);
105 else
106 VLOG(1) << "Ignoring short protected block of length: "
107 << (end_pos - start_pos);
108 }
109
110 // 2. If we actually found any EP3Bs, make a copy of the AU and then remove
111 // the EP3Bs in the copy (we can't modify the original).
112 if (adjustment) {
113 result.reset(new uint8_t[au_end_pos]);
114 uint8_t* temp = result.get();
115 memcpy(temp, au, au_end_pos);
116 for (auto epb_pos = epbs.rbegin(); epb_pos != epbs.rend(); ++epb_pos) {
117 RemoveByte(temp, *epb_pos, au_end_pos);
118 au_end_pos--;
119 }
120 au = temp;
121 VLOG(2) << "Copied AU and removed emulation prevention bytes: "
122 << adjustment;
123 }
124
125 // We now have either the original AU, or a copy with the EP3Bs removed.
126 // We also have an updated Ranges<int> indicating the protected blocks.
127 // Also au_end_pos has been adjusted to indicate the new au_size.
128
129 // 3. Use a new Ranges<int> to collect all the clear ranges. They will
130 // automatically be coalesced to minimize the number of (disjoint) ranges.
131 Ranges<int> clear_ranges;
132 int previous_pos = 0;
133 for (size_t i = 0; i < adjusted_protected_blocks.size(); i++) {
134 int start_pos = adjusted_protected_blocks.start(i);
135 int end_pos = adjusted_protected_blocks.end(i);
136 // Add the clear range prior to this protected block.
137 clear_ranges.Add(previous_pos, start_pos);
138 int block_size = end_pos - start_pos;
139 DCHECK_GT(block_size, kSampleAESMaxUnprotectedNALULength);
140 // Add the clear leader.
141 clear_ranges.Add(start_pos, start_pos + kSampleAESClearLeaderSize);
142 block_size -= kSampleAESClearLeaderSize;
143 // The bytes beyond an integral multiple of AES blocks (16 bytes) are to be
144 // left clear. Also, if the last 16 bytes would be the only block in a
145 // pattern unit (160 bytes), they are also left clear.
146 int residual_bytes = block_size % kSampleAESPatternUnit;
147 if (residual_bytes > 16)
148 residual_bytes = residual_bytes % 16;
149 clear_ranges.Add(end_pos - residual_bytes, end_pos);
150 previous_pos = end_pos;
151 }
152 // Add the trailing bytes, if any, beyond the last protected block.
153 clear_ranges.Add(previous_pos, au_end_pos);
154
155 // 4. Convert the disjoint set of clear ranges into subsample entries. Each
156 // subsample entry is a count of clear bytes followed by a count of protected
157 // bytes.
158 subsamples->clear();
159 for (size_t i = 0; i < clear_ranges.size(); i++) {
160 int start_pos = clear_ranges.start(i);
161 int end_pos = clear_ranges.end(i);
162 int clear_size = end_pos - start_pos;
163 int encrypt_end_pos = au_end_pos;
164
165 if (i + 1 < clear_ranges.size())
166 encrypt_end_pos = clear_ranges.start(i + 1);
167 SubsampleEntry subsample(clear_size, encrypt_end_pos - end_pos);
168 subsamples->push_back(subsample);
169 }
170 return result;
171 }
172
173 } // namespace
174 #endif // BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
175
26 // An AUD NALU is at least 4 bytes: 176 // An AUD NALU is at least 4 bytes:
27 // 3 bytes for the start code + 1 byte for the NALU type. 177 // 3 bytes for the start code + 1 byte for the NALU type.
28 const int kMinAUDSize = 4; 178 const int kMinAUDSize = 4;
29 179
30 EsParserH264::EsParserH264( 180 EsParserH264::EsParserH264(const NewVideoConfigCB& new_video_config_cb,
31 const NewVideoConfigCB& new_video_config_cb, 181 const EmitBufferCB& emit_buffer_cb)
32 const EmitBufferCB& emit_buffer_cb)
33 : es_adapter_(new_video_config_cb, emit_buffer_cb), 182 : es_adapter_(new_video_config_cb, emit_buffer_cb),
34 h264_parser_(new H264Parser()), 183 h264_parser_(new H264Parser()),
35 current_access_unit_pos_(0), 184 current_access_unit_pos_(0),
36 next_access_unit_pos_(0) { 185 next_access_unit_pos_(0)
186 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
187 ,
188 use_hls_sample_aes_(false),
189 get_decrypt_config_cb_()
190 #endif
191 {
37 } 192 }
38 193
194 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
195 EsParserH264::EsParserH264(const NewVideoConfigCB& new_video_config_cb,
196 const EmitBufferCB& emit_buffer_cb,
197 bool use_hls_sample_aes,
198 const GetDecryptConfigCB& get_decrypt_config_cb)
199 : es_adapter_(new_video_config_cb, emit_buffer_cb),
200 h264_parser_(new H264Parser()),
201 current_access_unit_pos_(0),
202 next_access_unit_pos_(0),
203 use_hls_sample_aes_(use_hls_sample_aes),
204 get_decrypt_config_cb_(get_decrypt_config_cb) {
205 DCHECK_EQ(!get_decrypt_config_cb_.is_null(), use_hls_sample_aes_);
206 }
207 #endif
208
39 EsParserH264::~EsParserH264() { 209 EsParserH264::~EsParserH264() {
40 } 210 }
41 211
42 void EsParserH264::Flush() { 212 void EsParserH264::Flush() {
43 DVLOG(1) << __FUNCTION__; 213 DVLOG(1) << __FUNCTION__;
44 if (!FindAUD(&current_access_unit_pos_)) 214 if (!FindAUD(&current_access_unit_pos_))
45 return; 215 return;
46 216
47 // Simulate an additional AUD to force emitting the last access unit 217 // Simulate an additional AUD to force emitting the last access unit
48 // which is assumed to be complete at this point. 218 // which is assumed to be complete at this point.
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) { 346 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
177 // Only accept an invalid SPS/PPS at the beginning when the stream 347 // Only accept an invalid SPS/PPS at the beginning when the stream
178 // does not necessarily start with an SPS/PPS/IDR. 348 // does not necessarily start with an SPS/PPS/IDR.
179 // TODO(damienv): Should be able to differentiate a missing SPS/PPS 349 // TODO(damienv): Should be able to differentiate a missing SPS/PPS
180 // from a slice header parsing error. 350 // from a slice header parsing error.
181 if (last_video_decoder_config_.IsValidConfig()) 351 if (last_video_decoder_config_.IsValidConfig())
182 return false; 352 return false;
183 } else { 353 } else {
184 pps_id_for_access_unit = shdr.pic_parameter_set_id; 354 pps_id_for_access_unit = shdr.pic_parameter_set_id;
185 } 355 }
356 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
357 // With HLS SampleAES, protected blocks in H.264 consist of IDR and non-
358 // IDR slices that are more than 48 bytes in length.
359 if (use_hls_sample_aes_ &&
360 nalu.size > kSampleAESMaxUnprotectedNALULength) {
361 int64_t nal_begin = nalu.data - es;
362 protected_blocks_.Add(nal_begin, nal_begin + nalu.size);
363 }
364 #endif
186 break; 365 break;
187 } 366 }
188 default: { 367 default: {
189 DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type; 368 DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type;
190 } 369 }
191 } 370 }
192 } 371 }
193 372
194 // Emit a frame and move the stream to the next AUD position. 373 // Emit a frame and move the stream to the next AUD position.
195 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size, 374 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 // does not necessarily start with an SPS/PPS/IDR. 407 // does not necessarily start with an SPS/PPS/IDR.
229 // In this case, the initial frames are conveyed to the upper layer with 408 // In this case, the initial frames are conveyed to the upper layer with
230 // an invalid VideoDecoderConfig and it's up to the upper layer 409 // an invalid VideoDecoderConfig and it's up to the upper layer
231 // to process this kind of frame accordingly. 410 // to process this kind of frame accordingly.
232 if (last_video_decoder_config_.IsValidConfig()) 411 if (last_video_decoder_config_.IsValidConfig())
233 return false; 412 return false;
234 } else { 413 } else {
235 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id); 414 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
236 if (!sps) 415 if (!sps)
237 return false; 416 return false;
238 RCHECK(UpdateVideoDecoderConfig(sps, Unencrypted())); 417 EncryptionScheme scheme = Unencrypted();
418 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
419 if (use_hls_sample_aes_) {
420 // Note that for SampleAES the (encrypt,skip) pattern is constant.
421 scheme =
422 EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CBC,
423 EncryptionScheme::Pattern(kSampleAESEncryptBlocks,
424 kSampleAESSkipBlocks));
425 }
426 #endif
427 RCHECK(UpdateVideoDecoderConfig(sps, scheme));
239 } 428 }
240 429
241 // Emit a frame. 430 // Emit a frame.
242 DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_ 431 DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
243 << " size=" << access_unit_size; 432 << " size=" << access_unit_size;
244 int es_size; 433 int es_size;
245 const uint8_t* es; 434 const uint8_t* es;
246 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size); 435 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
247 CHECK_GE(es_size, access_unit_size); 436 CHECK_GE(es_size, access_unit_size);
248 437
438 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
439 std::unique_ptr<uint8_t[]> adjusted_au;
440 std::vector<SubsampleEntry> subsamples;
441 if (use_hls_sample_aes_) {
442 adjusted_au = AdjustAUForSampleAES(es, &access_unit_size, protected_blocks_,
443 &subsamples);
444 protected_blocks_.clear();
445 if (adjusted_au)
446 es = adjusted_au.get();
447 }
448 #endif
449
249 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId 450 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
250 // type and allow multiple video tracks. See https://crbug.com/341581. 451 // type and allow multiple video tracks. See https://crbug.com/341581.
251 scoped_refptr<StreamParserBuffer> stream_parser_buffer = 452 scoped_refptr<StreamParserBuffer> stream_parser_buffer =
252 StreamParserBuffer::CopyFrom(es, access_unit_size, is_key_frame, 453 StreamParserBuffer::CopyFrom(es, access_unit_size, is_key_frame,
253 DemuxerStream::VIDEO, kMp2tVideoTrackId); 454 DemuxerStream::VIDEO, kMp2tVideoTrackId);
254 stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts); 455 stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
255 stream_parser_buffer->set_timestamp(current_timing_desc.pts); 456 stream_parser_buffer->set_timestamp(current_timing_desc.pts);
457 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
458 if (use_hls_sample_aes_) {
459 DCHECK(!get_decrypt_config_cb_.is_null());
460 const DecryptConfig* base_decrypt_config = get_decrypt_config_cb_.Run();
461 RCHECK(base_decrypt_config);
462 std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
463 base_decrypt_config->key_id(), base_decrypt_config->iv(), subsamples));
464 stream_parser_buffer->set_decrypt_config(std::move(decrypt_config));
465 }
466 #endif
256 return es_adapter_.OnNewBuffer(stream_parser_buffer); 467 return es_adapter_.OnNewBuffer(stream_parser_buffer);
257 } 468 }
258 469
259 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps, 470 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps,
260 const EncryptionScheme& scheme) { 471 const EncryptionScheme& scheme) {
261 // Set the SAR to 1 when not specified in the H264 stream. 472 // Set the SAR to 1 when not specified in the H264 stream.
262 int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width; 473 int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width;
263 int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height; 474 int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height;
264 475
265 base::Optional<gfx::Size> coded_size = sps->GetCodedSize(); 476 base::Optional<gfx::Size> coded_size = sps->GetCodedSize();
(...skipping 30 matching lines...) Expand all
296 << " height=" << sps->sar_height; 507 << " height=" << sps->sar_height;
297 last_video_decoder_config_ = video_decoder_config; 508 last_video_decoder_config_ = video_decoder_config;
298 es_adapter_.OnConfigChanged(video_decoder_config); 509 es_adapter_.OnConfigChanged(video_decoder_config);
299 } 510 }
300 511
301 return true; 512 return true;
302 } 513 }
303 514
304 } // namespace mp2t 515 } // namespace mp2t
305 } // namespace media 516 } // namespace media
OLDNEW
« no previous file with comments | « media/formats/mp2t/es_parser_h264.h ('k') | media/formats/mp2t/mp2t_stream_parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698