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

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: move some gn defs Created 4 years, 8 months 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
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 "base/logging.h" 7 #include "base/logging.h"
8 #include "base/numerics/safe_conversions.h" 8 #include "base/numerics/safe_conversions.h"
9 #include "media/base/decrypt_config.h"
9 #include "media/base/encryption_scheme.h" 10 #include "media/base/encryption_scheme.h"
10 #include "media/base/media_util.h" 11 #include "media/base/media_util.h"
11 #include "media/base/stream_parser_buffer.h" 12 #include "media/base/stream_parser_buffer.h"
12 #include "media/base/timestamp_constants.h" 13 #include "media/base/timestamp_constants.h"
13 #include "media/base/video_frame.h" 14 #include "media/base/video_frame.h"
14 #include "media/filters/h264_parser.h" 15 #include "media/filters/h264_parser.h"
15 #include "media/formats/common/offset_byte_queue.h" 16 #include "media/formats/common/offset_byte_queue.h"
16 #include "media/formats/mp2t/mp2t_common.h" 17 #include "media/formats/mp2t/mp2t_common.h"
17 #include "ui/gfx/geometry/rect.h" 18 #include "ui/gfx/geometry/rect.h"
18 #include "ui/gfx/geometry/size.h" 19 #include "ui/gfx/geometry/size.h"
(...skipping 23 matching lines...) Expand all
42 return H264PROFILE_SCALABLEHIGH; 43 return H264PROFILE_SCALABLEHIGH;
43 case H264SPS::kProfileIDStereoHigh: 44 case H264SPS::kProfileIDStereoHigh:
44 return H264PROFILE_STEREOHIGH; 45 return H264PROFILE_STEREOHIGH;
45 case H264SPS::kProfileIDSMultiviewHigh: 46 case H264SPS::kProfileIDSMultiviewHigh:
46 return H264PROFILE_MULTIVIEWHIGH; 47 return H264PROFILE_MULTIVIEWHIGH;
47 } 48 }
48 NOTREACHED() << "unknown video profile: " << profile_idc; 49 NOTREACHED() << "unknown video profile: " << profile_idc;
49 return VIDEO_CODEC_PROFILE_UNKNOWN; 50 return VIDEO_CODEC_PROFILE_UNKNOWN;
50 } 51 }
51 52
53 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
54
55 const int kSampleAESMaxUnprotectedNALULength = 48;
56 const int kSampleAESClearLeaderSize = 32;
57 const int kSampleAESEncryptBlocks = 1;
ddorwin 2016/04/12 00:40:47 Do these only apply to H.264 or should they be som
dougsteed 2016/05/08 23:18:44 Only H.264
58 const int kSampleAESSkipBlocks = 9;
59 const int kSampleAESPatternUnit =
60 (kSampleAESEncryptBlocks + kSampleAESSkipBlocks) * 16;
61
62 // Attempts to find the first or only EP3B (emulation prevention 3 byte) in
63 // the part of the |buffer| between |start_pos| and |end_pos|. Returns the
64 // position of the EP3B, or 0 if there are none.
65 // Note: the EP3B always follows two zero bytes, so the value 0 can never be a
66 // valid position.
67 int FindEP3B(const uint8_t* buffer, int start_pos, int end_pos) {
68 const uint8_t* data = buffer + start_pos;
69 int data_size = end_pos - start_pos;
70 DCHECK_GE(data_size, 0);
71 int bytes_left = data_size;
72
73 while (bytes_left >= 4) {
74 if (data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x03 &&
75 data[3] <= 0x03) {
76 return (data - buffer) + 2;
77 }
78 ++data;
79 --bytes_left;
80 }
81 return 0;
82 }
83
84 // Remove the byte at |pos| in the |buffer| and close up the gap, moving all the
85 // bytes from [pos + 1, end_pos) to [pos, end_pos - 1).
86 void RemoveByte(uint8_t* buffer, int pos, int end_pos) {
87 memmove(&buffer[pos], &buffer[pos + 1], end_pos - pos - 1);
88 }
89
90 // Given an Access Unit pointed to by |au| of size |au_size|, removes emulation
91 // prevention 3 bytes (EP3B) from within the |protected_blocks|. Also computes
92 // the |subsamples| vector describing the resulting AU.
93 // Returns the allocated buffer holding the adjusted copy, or NULL if no size
94 // adjustment was necessary.
95 scoped_ptr<uint8_t[]> AdjustAUForSampleAES(
96 const uint8_t* au,
97 int* au_size,
98 const Ranges<int>& protected_blocks,
99 std::vector<SubsampleEntry>* subsamples) {
100 DCHECK(subsamples);
101 DCHECK(au_size);
102 scoped_ptr<uint8_t[]> result;
103 int& au_end_pos = *au_size;
104
105 // 1. Considering each protected block in turn, find any emulation prevention
106 // 3 bytes (EP3B) within it, keeping track of their positions. While doing so,
107 // produce a revised Ranges<int> reflecting the new protected block positions
108 // that will apply after we have removed the EP3Bs.
109 Ranges<int> adjusted_protected_blocks;
110 std::vector<int> epbs;
111 int adjustment = 0;
112 for (size_t i = 0; i < protected_blocks.size(); i++) {
113 int start_pos = protected_blocks.start(i) - adjustment;
114 int end_pos = protected_blocks.end(i) - adjustment;
115 int search_pos = start_pos;
116 int epb_pos;
117 int block_adjustment = 0;
118 while ((epb_pos = FindEP3B(au, search_pos, end_pos))) {
119 epbs.push_back(epb_pos);
120 block_adjustment++;
121 search_pos = epb_pos + 2;
122 }
123 end_pos -= block_adjustment;
124 adjustment += block_adjustment;
125 adjusted_protected_blocks.Add(start_pos, end_pos);
126 }
127
128 // 2. If we actually found any EP3Bs, make a copy of the AU and then remove
129 // the EP3Bs in the copy (we can't modify the original).
130 if (adjustment) {
131 result.reset(new uint8_t[au_end_pos]);
132 uint8_t* temp = result.get();
133 memcpy(temp, au, au_end_pos);
134 for (auto epb_pos = epbs.rbegin(); epb_pos != epbs.rend(); ++epb_pos) {
135 RemoveByte(temp, *epb_pos, au_end_pos);
136 au_end_pos--;
137 }
138 au = temp;
139 }
140
141 // We now have either the original AU, or a copy with the EP3Bs removed.
142 // We also have an updated Ranges<int> indicating the protected blocks.
143 // Also au_end_pos has been adjusted to indicate the new au_size.
144
145 // 3. Use a new Ranges<int> to collect all the clear ranges. They will
146 // automatically be coalesced to minimize the number of (disjoint) ranges.
147 Ranges<int> clear_ranges;
148 int previous_pos = 0;
149 for (size_t i = 0; i < adjusted_protected_blocks.size(); i++) {
150 int start_pos = adjusted_protected_blocks.start(i);
151 int end_pos = adjusted_protected_blocks.end(i);
152 // Add the clear range prior to this protected block.
153 clear_ranges.Add(previous_pos, start_pos);
154 int block_size = end_pos - start_pos;
155 DCHECK_GT(block_size, kSampleAESMaxUnprotectedNALULength);
156 // Add the clear leader.
157 clear_ranges.Add(start_pos, start_pos + kSampleAESClearLeaderSize);
158 block_size -= kSampleAESClearLeaderSize;
159 // The bytes beyond an integral multiple of AES blocks (16 bytes) are to be
160 // left clear. Also, if the last 16 bytes would be the only block in a
161 // pattern unit (160 bytes), they are also left clear.
162 int residual_bytes = block_size % kSampleAESPatternUnit;
163 if (residual_bytes > 16)
164 residual_bytes = residual_bytes % 16;
165 clear_ranges.Add(end_pos - residual_bytes, end_pos);
166 previous_pos = end_pos;
167 }
168 // Add the trailing bytes, if any, beyond the last protected block.
169 clear_ranges.Add(previous_pos, au_end_pos);
170
171 // 4. Convert the disjoint set of clear ranges into subsample entries. Each
172 // subsample entry is a count of clear bytes followed by a count of protected
173 // bytes.
174 subsamples->clear();
175 for (size_t i = 0; i < clear_ranges.size(); i++) {
176 int start_pos = clear_ranges.start(i);
177 int end_pos = clear_ranges.end(i);
178 int clear_size = end_pos - start_pos;
179 int encrypt_end_pos = au_end_pos;
180
181 if (i + 1 < clear_ranges.size())
182 encrypt_end_pos = clear_ranges.start(i + 1);
183 SubsampleEntry subsample(clear_size, encrypt_end_pos - end_pos);
184 subsamples->push_back(subsample);
185 }
186 return result;
187 }
188
189 #endif
ddorwin 2016/04/12 00:40:47 // BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
dougsteed 2016/05/08 23:18:44 Done.
52 } // namespace 190 } // namespace
53 191
54 // An AUD NALU is at least 4 bytes: 192 // An AUD NALU is at least 4 bytes:
55 // 3 bytes for the start code + 1 byte for the NALU type. 193 // 3 bytes for the start code + 1 byte for the NALU type.
56 const int kMinAUDSize = 4; 194 const int kMinAUDSize = 4;
57 195
58 EsParserH264::EsParserH264( 196 EsParserH264::EsParserH264(const NewVideoConfigCB& new_video_config_cb,
59 const NewVideoConfigCB& new_video_config_cb, 197 const EmitBufferCB& emit_buffer_cb)
60 const EmitBufferCB& emit_buffer_cb)
61 : es_adapter_(new_video_config_cb, emit_buffer_cb), 198 : es_adapter_(new_video_config_cb, emit_buffer_cb),
62 h264_parser_(new H264Parser()), 199 h264_parser_(new H264Parser()),
63 current_access_unit_pos_(0), 200 current_access_unit_pos_(0),
64 next_access_unit_pos_(0) { 201 next_access_unit_pos_(0)
202 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
203 ,
204 get_decrypt_config_cb_(),
205 use_hls_sample_aes_(false)
206 #endif
207 {
65 } 208 }
66 209
210 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
211 EsParserH264::EsParserH264(const NewVideoConfigCB& new_video_config_cb,
212 const EmitBufferCB& emit_buffer_cb,
213 const GetDecryptConfigCB& get_decrypt_config_cb,
214 bool use_hls_sample_aes)
215 : es_adapter_(new_video_config_cb, emit_buffer_cb),
216 h264_parser_(new H264Parser()),
217 current_access_unit_pos_(0),
218 next_access_unit_pos_(0),
219 get_decrypt_config_cb_(get_decrypt_config_cb),
220 use_hls_sample_aes_(use_hls_sample_aes) {}
221 #endif
222
67 EsParserH264::~EsParserH264() { 223 EsParserH264::~EsParserH264() {
68 } 224 }
69 225
70 void EsParserH264::Flush() { 226 void EsParserH264::Flush() {
71 DVLOG(1) << __FUNCTION__; 227 DVLOG(1) << __FUNCTION__;
72 if (!FindAUD(&current_access_unit_pos_)) 228 if (!FindAUD(&current_access_unit_pos_))
73 return; 229 return;
74 230
75 // Simulate an additional AUD to force emitting the last access unit 231 // Simulate an additional AUD to force emitting the last access unit
76 // which is assumed to be complete at this point. 232 // which is assumed to be complete at this point.
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) { 360 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
205 // Only accept an invalid SPS/PPS at the beginning when the stream 361 // Only accept an invalid SPS/PPS at the beginning when the stream
206 // does not necessarily start with an SPS/PPS/IDR. 362 // does not necessarily start with an SPS/PPS/IDR.
207 // TODO(damienv): Should be able to differentiate a missing SPS/PPS 363 // TODO(damienv): Should be able to differentiate a missing SPS/PPS
208 // from a slice header parsing error. 364 // from a slice header parsing error.
209 if (last_video_decoder_config_.IsValidConfig()) 365 if (last_video_decoder_config_.IsValidConfig())
210 return false; 366 return false;
211 } else { 367 } else {
212 pps_id_for_access_unit = shdr.pic_parameter_set_id; 368 pps_id_for_access_unit = shdr.pic_parameter_set_id;
213 } 369 }
370 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
371 // With HLS SampleAES, protected blocks in H.264 consist of IDR and non-
372 // IDR slices that are more than 48 bytes in length.
373 if (use_hls_sample_aes_ &&
374 nalu.size > kSampleAESMaxUnprotectedNALULength) {
375 int64_t nal_begin = nalu.data - es;
376 protected_blocks_.Add(nal_begin, nal_begin + nalu.size);
377 }
378 #endif
214 break; 379 break;
215 } 380 }
216 default: { 381 default: {
217 DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type; 382 DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type;
218 } 383 }
219 } 384 }
220 } 385 }
221 386
222 // Emit a frame and move the stream to the next AUD position. 387 // Emit a frame and move the stream to the next AUD position.
223 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size, 388 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 // does not necessarily start with an SPS/PPS/IDR. 422 // does not necessarily start with an SPS/PPS/IDR.
258 // In this case, the initial frames are conveyed to the upper layer with 423 // In this case, the initial frames are conveyed to the upper layer with
259 // an invalid VideoDecoderConfig and it's up to the upper layer 424 // an invalid VideoDecoderConfig and it's up to the upper layer
260 // to process this kind of frame accordingly. 425 // to process this kind of frame accordingly.
261 if (last_video_decoder_config_.IsValidConfig()) 426 if (last_video_decoder_config_.IsValidConfig())
262 return false; 427 return false;
263 } else { 428 } else {
264 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id); 429 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
265 if (!sps) 430 if (!sps)
266 return false; 431 return false;
267 RCHECK(UpdateVideoDecoderConfig(sps, Unencrypted())); 432 EncryptionScheme scheme = Unencrypted();
433 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
434 if (use_hls_sample_aes_) {
435 // Note that for SampleAES the (encrypt,skip) pattern is constant.
436 scheme =
437 EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CBC,
ddorwin 2016/04/12 00:40:47 Since this is fixed (and these constants may be ne
dougsteed 2016/05/08 23:18:44 This is currently the only place it's needed. Mayb
438 EncryptionScheme::Pattern(kSampleAESEncryptBlocks,
439 kSampleAESSkipBlocks));
440 }
441 #endif
442 RCHECK(UpdateVideoDecoderConfig(sps, scheme));
268 } 443 }
269 444
270 // Emit a frame. 445 // Emit a frame.
271 DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_ 446 DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
272 << " size=" << access_unit_size; 447 << " size=" << access_unit_size;
273 int es_size; 448 int es_size;
274 const uint8_t* es; 449 const uint8_t* es;
275 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size); 450 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
276 CHECK_GE(es_size, access_unit_size); 451 CHECK_GE(es_size, access_unit_size);
277 452
453 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
454 scoped_ptr<uint8_t[]> adjusted_au;
455 std::vector<SubsampleEntry> subsamples;
456 if (use_hls_sample_aes_) {
457 adjusted_au = AdjustAUForSampleAES(es, &access_unit_size, protected_blocks_,
458 &subsamples);
459 protected_blocks_.clear();
460 if (adjusted_au)
461 es = adjusted_au.get();
462 }
463 #endif
464
278 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId 465 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
279 // type and allow multiple video tracks. See https://crbug.com/341581. 466 // type and allow multiple video tracks. See https://crbug.com/341581.
280 scoped_refptr<StreamParserBuffer> stream_parser_buffer = 467 scoped_refptr<StreamParserBuffer> stream_parser_buffer =
281 StreamParserBuffer::CopyFrom( 468 StreamParserBuffer::CopyFrom(
282 es, 469 es,
283 access_unit_size, 470 access_unit_size,
284 is_key_frame, 471 is_key_frame,
285 DemuxerStream::VIDEO, 472 DemuxerStream::VIDEO,
286 0); 473 0);
287 stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts); 474 stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
288 stream_parser_buffer->set_timestamp(current_timing_desc.pts); 475 stream_parser_buffer->set_timestamp(current_timing_desc.pts);
476 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
477 if (use_hls_sample_aes_) {
478 DCHECK(!get_decrypt_config_cb_.is_null());
479 const DecryptConfig* base_decrypt_config = get_decrypt_config_cb_.Run();
480 RCHECK(base_decrypt_config);
481 scoped_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
482 base_decrypt_config->key_id(), base_decrypt_config->iv(), subsamples));
483 stream_parser_buffer->set_decrypt_config(std::move(decrypt_config));
484 }
485 #endif
289 return es_adapter_.OnNewBuffer(stream_parser_buffer); 486 return es_adapter_.OnNewBuffer(stream_parser_buffer);
290 } 487 }
291 488
292 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps, 489 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps,
293 const EncryptionScheme& scheme) { 490 const EncryptionScheme& scheme) {
294 // Set the SAR to 1 when not specified in the H264 stream. 491 // Set the SAR to 1 when not specified in the H264 stream.
295 int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width; 492 int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width;
296 int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height; 493 int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height;
297 494
298 // TODO(damienv): a MAP unit can be either 16 or 32 pixels. 495 // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 << " height=" << sps->sar_height; 527 << " height=" << sps->sar_height;
331 last_video_decoder_config_ = video_decoder_config; 528 last_video_decoder_config_ = video_decoder_config;
332 es_adapter_.OnConfigChanged(video_decoder_config); 529 es_adapter_.OnConfigChanged(video_decoder_config);
333 } 530 }
334 531
335 return true; 532 return true;
336 } 533 }
337 534
338 } // namespace mp2t 535 } // namespace mp2t
339 } // namespace media 536 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698