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

Side by Side Diff: media/formats/mp2t/es_parser_adts.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, 9 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_adts.h" 5 #include "media/formats/mp2t/es_parser_adts.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <vector> 9 #include <vector>
10 10
(...skipping 11 matching lines...) Expand all
22 #include "media/formats/mpeg/adts_header_parser.h" 22 #include "media/formats/mpeg/adts_header_parser.h"
23 23
24 namespace media { 24 namespace media {
25 25
26 static int ExtractAdtsFrameSize(const uint8_t* adts_header) { 26 static int ExtractAdtsFrameSize(const uint8_t* adts_header) {
27 return ((static_cast<int>(adts_header[5]) >> 5) | 27 return ((static_cast<int>(adts_header[5]) >> 5) |
28 (static_cast<int>(adts_header[4]) << 3) | 28 (static_cast<int>(adts_header[4]) << 3) |
29 ((static_cast<int>(adts_header[3]) & 0x3) << 11)); 29 ((static_cast<int>(adts_header[3]) & 0x3) << 11));
30 } 30 }
31 31
32 static int AdtsHeaderSize(const uint8_t* adts_header) {
33 // protection absent bit: set to 1 if there is no CRC and 0 if there is CRC
34 return (adts_header[1] & 0x1) ? kADTSHeaderSizeNoCrc : kADTSHeaderSizeWithCrc;
35 }
36
32 // Return true if buf corresponds to an ADTS syncword. 37 // Return true if buf corresponds to an ADTS syncword.
33 // |buf| size must be at least 2. 38 // |buf| size must be at least 2.
34 static bool isAdtsSyncWord(const uint8_t* buf) { 39 static bool isAdtsSyncWord(const uint8_t* buf) {
35 // The first 12 bits must be 1. 40 // The first 12 bits must be 1.
36 // The layer field (2 bits) must be set to 0. 41 // The layer field (2 bits) must be set to 0.
37 return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0); 42 return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0);
38 } 43 }
39 44
40 namespace mp2t { 45 namespace mp2t {
41 46
42 struct EsParserAdts::AdtsFrame { 47 struct EsParserAdts::AdtsFrame {
43 // Pointer to the ES data. 48 // Pointer to the ES data.
44 const uint8_t* data; 49 const uint8_t* data;
45 50
46 // Frame size; 51 // Frame size;
47 int size; 52 int size;
53 int header_size;
48 54
49 // Frame offset in the ES queue. 55 // Frame offset in the ES queue.
50 int64_t queue_offset; 56 int64_t queue_offset;
51 }; 57 };
52 58
53 bool EsParserAdts::LookForAdtsFrame(AdtsFrame* adts_frame) { 59 bool EsParserAdts::LookForAdtsFrame(AdtsFrame* adts_frame) {
54 int es_size; 60 int es_size;
55 const uint8_t* es; 61 const uint8_t* es;
56 es_queue_->Peek(&es, &es_size); 62 es_queue_->Peek(&es, &es_size);
57 63
58 int max_offset = es_size - kADTSHeaderMinSize; 64 int max_offset = es_size - kADTSHeaderMinSize;
59 if (max_offset <= 0) 65 if (max_offset <= 0)
60 return false; 66 return false;
61 67
62 for (int offset = 0; offset < max_offset; offset++) { 68 for (int offset = 0; offset < max_offset; offset++) {
63 const uint8_t* cur_buf = &es[offset]; 69 const uint8_t* cur_buf = &es[offset];
64 if (!isAdtsSyncWord(cur_buf)) 70 if (!isAdtsSyncWord(cur_buf))
65 continue; 71 continue;
66 72
67 int frame_size = ExtractAdtsFrameSize(cur_buf); 73 int frame_size = ExtractAdtsFrameSize(cur_buf);
68 if (frame_size < kADTSHeaderMinSize) { 74 if (frame_size < kADTSHeaderMinSize) {
69 // Too short to be an ADTS frame. 75 // Too short to be an ADTS frame.
70 continue; 76 continue;
71 } 77 }
78 int header_size = AdtsHeaderSize(cur_buf);
72 79
73 int remaining_size = es_size - offset; 80 int remaining_size = es_size - offset;
74 if (remaining_size < frame_size) { 81 if (remaining_size < frame_size) {
75 // Not a full frame: will resume when we have more data. 82 // Not a full frame: will resume when we have more data.
76 es_queue_->Pop(offset); 83 es_queue_->Pop(offset);
77 return false; 84 return false;
78 } 85 }
79 86
80 // Check whether there is another frame 87 // Check whether there is another frame
81 // |size| apart from the current one. 88 // |size| apart from the current one.
82 if (remaining_size >= frame_size + 2 && 89 if (remaining_size >= frame_size + 2 &&
83 !isAdtsSyncWord(&cur_buf[frame_size])) { 90 !isAdtsSyncWord(&cur_buf[frame_size])) {
84 continue; 91 continue;
85 } 92 }
86 93
87 es_queue_->Pop(offset); 94 es_queue_->Pop(offset);
88 es_queue_->Peek(&adts_frame->data, &es_size); 95 es_queue_->Peek(&adts_frame->data, &es_size);
89 adts_frame->queue_offset = es_queue_->head(); 96 adts_frame->queue_offset = es_queue_->head();
90 adts_frame->size = frame_size; 97 adts_frame->size = frame_size;
98 adts_frame->header_size = header_size;
91 DVLOG(LOG_LEVEL_ES) 99 DVLOG(LOG_LEVEL_ES)
92 << "ADTS syncword @ pos=" << adts_frame->queue_offset 100 << "ADTS syncword @ pos=" << adts_frame->queue_offset
93 << " frame_size=" << adts_frame->size; 101 << " frame_size=" << adts_frame->size;
94 DVLOG(LOG_LEVEL_ES) 102 DVLOG(LOG_LEVEL_ES)
95 << "ADTS header: " 103 << "ADTS header: "
96 << base::HexEncode(adts_frame->data, kADTSHeaderMinSize); 104 << base::HexEncode(adts_frame->data, kADTSHeaderMinSize);
97 return true; 105 return true;
98 } 106 }
99 107
100 es_queue_->Pop(max_offset); 108 es_queue_->Pop(max_offset);
101 return false; 109 return false;
102 } 110 }
103 111
104 void EsParserAdts::SkipAdtsFrame(const AdtsFrame& adts_frame) { 112 void EsParserAdts::SkipAdtsFrame(const AdtsFrame& adts_frame) {
105 DCHECK_EQ(adts_frame.queue_offset, es_queue_->head()); 113 DCHECK_EQ(adts_frame.queue_offset, es_queue_->head());
106 es_queue_->Pop(adts_frame.size); 114 es_queue_->Pop(adts_frame.size);
107 } 115 }
108 116
109 EsParserAdts::EsParserAdts( 117 EsParserAdts::EsParserAdts(const NewAudioConfigCB& new_audio_config_cb,
110 const NewAudioConfigCB& new_audio_config_cb, 118 const EmitBufferCB& emit_buffer_cb,
111 const EmitBufferCB& emit_buffer_cb, 119 bool sbr_in_mimetype)
112 bool sbr_in_mimetype) 120 : new_audio_config_cb_(new_audio_config_cb),
113 : new_audio_config_cb_(new_audio_config_cb), 121 emit_buffer_cb_(emit_buffer_cb),
114 emit_buffer_cb_(emit_buffer_cb), 122 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
115 sbr_in_mimetype_(sbr_in_mimetype) { 123 get_decrypt_config_cb_(),
124 use_hls_sample_aes_(false),
125 #endif
126 sbr_in_mimetype_(sbr_in_mimetype) {
116 } 127 }
117 128
129 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
130 EsParserAdts::EsParserAdts(const NewAudioConfigCB& new_audio_config_cb,
131 const EmitBufferCB& emit_buffer_cb,
132 const GetDecryptConfigCB& get_decrypt_config_cb,
133 bool use_hls_sample_aes,
134 bool sbr_in_mimetype)
135 : new_audio_config_cb_(new_audio_config_cb),
136 emit_buffer_cb_(emit_buffer_cb),
137 get_decrypt_config_cb_(get_decrypt_config_cb),
138 use_hls_sample_aes_(use_hls_sample_aes),
139 sbr_in_mimetype_(sbr_in_mimetype) {}
140 #endif
141
118 EsParserAdts::~EsParserAdts() { 142 EsParserAdts::~EsParserAdts() {
119 } 143 }
120 144
145 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
146 void EsParserAdts::CalculateSubsamplesForAdtsFrame(
147 const AdtsFrame& adts_frame,
148 std::vector<SubsampleEntry>* subsamples) {
149 DCHECK(subsamples);
150 subsamples->clear();
151 int data_size = adts_frame.size - adts_frame.header_size;
152 int residue = data_size % 16;
153 int clear_bytes = adts_frame.header_size;
154 int encrypted_bytes = 0;
155 if (data_size <= 16) {
156 clear_bytes += data_size;
157 residue = 0;
158 } else {
159 clear_bytes += 16;
160 encrypted_bytes = adts_frame.size - clear_bytes - residue;
161 }
162 SubsampleEntry subsample(clear_bytes, encrypted_bytes);
163 subsamples->push_back(subsample);
164 if (residue) {
165 subsample.clear_bytes = residue;
166 subsample.cypher_bytes = 0;
167 subsamples->push_back(subsample);
168 }
169 }
170 #endif
171
121 bool EsParserAdts::ParseFromEsQueue() { 172 bool EsParserAdts::ParseFromEsQueue() {
122 // Look for every ADTS frame in the ES buffer. 173 // Look for every ADTS frame in the ES buffer.
123 AdtsFrame adts_frame; 174 AdtsFrame adts_frame;
124 while (LookForAdtsFrame(&adts_frame)) { 175 while (LookForAdtsFrame(&adts_frame)) {
125 // Update the audio configuration if needed. 176 // Update the audio configuration if needed.
126 DCHECK_GE(adts_frame.size, kADTSHeaderMinSize); 177 DCHECK_GE(adts_frame.size, kADTSHeaderMinSize);
127 if (!UpdateAudioConfiguration(adts_frame.data)) 178 if (!UpdateAudioConfiguration(adts_frame.data))
128 return false; 179 return false;
129 180
130 // Get the PTS & the duration of this access unit. 181 // Get the PTS & the duration of this access unit.
(...skipping 19 matching lines...) Expand all
150 scoped_refptr<StreamParserBuffer> stream_parser_buffer = 201 scoped_refptr<StreamParserBuffer> stream_parser_buffer =
151 StreamParserBuffer::CopyFrom( 202 StreamParserBuffer::CopyFrom(
152 adts_frame.data, 203 adts_frame.data,
153 adts_frame.size, 204 adts_frame.size,
154 is_key_frame, 205 is_key_frame,
155 DemuxerStream::AUDIO, 0); 206 DemuxerStream::AUDIO, 0);
156 stream_parser_buffer->set_timestamp(current_pts); 207 stream_parser_buffer->set_timestamp(current_pts);
157 stream_parser_buffer->SetDecodeTimestamp( 208 stream_parser_buffer->SetDecodeTimestamp(
158 DecodeTimestamp::FromPresentationTime(current_pts)); 209 DecodeTimestamp::FromPresentationTime(current_pts));
159 stream_parser_buffer->set_duration(frame_duration); 210 stream_parser_buffer->set_duration(frame_duration);
211 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
212 if (use_hls_sample_aes_) {
213 const DecryptConfig* base_decrypt_config = get_decrypt_config_cb_.Run();
214 RCHECK(base_decrypt_config);
215 std::vector<SubsampleEntry> subsamples;
216 CalculateSubsamplesForAdtsFrame(adts_frame, &subsamples);
217 scoped_ptr<DecryptConfig> decrypt_config(
218 new DecryptConfig(base_decrypt_config->key_id(),
219 base_decrypt_config->iv(), subsamples));
220 stream_parser_buffer->set_decrypt_config(std::move(decrypt_config));
221 }
222 #endif
160 emit_buffer_cb_.Run(stream_parser_buffer); 223 emit_buffer_cb_.Run(stream_parser_buffer);
161 224
162 // Update the PTS of the next frame. 225 // Update the PTS of the next frame.
163 audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame); 226 audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame);
164 227
165 // Skip the current frame. 228 // Skip the current frame.
166 SkipAdtsFrame(adts_frame); 229 SkipAdtsFrame(adts_frame);
167 } 230 }
168 231
169 return true; 232 return true;
170 } 233 }
171 234
172 void EsParserAdts::Flush() { 235 void EsParserAdts::Flush() {
173 } 236 }
174 237
175 void EsParserAdts::ResetInternal() { 238 void EsParserAdts::ResetInternal() {
176 last_audio_decoder_config_ = AudioDecoderConfig(); 239 last_audio_decoder_config_ = AudioDecoderConfig();
177 } 240 }
178 241
179 bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_header) { 242 bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_header) {
180 AudioDecoderConfig audio_decoder_config; 243 AudioDecoderConfig audio_decoder_config;
181 if (!ParseAdtsHeader(adts_header, sbr_in_mimetype_, &audio_decoder_config)) 244 EncryptionScheme scheme = Unencrypted();
245 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
246 if (use_hls_sample_aes_) {
247 scheme = EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CBC,
248 EncryptionScheme::Pattern());
249 }
250 #endif
251 if (!ParseAdtsHeader(adts_header, sbr_in_mimetype_, scheme,
252 &audio_decoder_config))
182 return false; 253 return false;
183 254
184 if (!audio_decoder_config.Matches(last_audio_decoder_config_)) { 255 if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
185 DVLOG(1) << "Sampling frequency: " 256 DVLOG(1) << "Sampling frequency: "
186 << audio_decoder_config.samples_per_second(); 257 << audio_decoder_config.samples_per_second();
187 DVLOG(1) << "Channel layout: " 258 DVLOG(1) << "Channel layout: "
188 << ChannelLayoutToString(audio_decoder_config.channel_layout()); 259 << ChannelLayoutToString(audio_decoder_config.channel_layout());
189 // Reset the timestamp helper to use a new time scale. 260 // Reset the timestamp helper to use a new time scale.
190 if (audio_timestamp_helper_ && 261 if (audio_timestamp_helper_ &&
191 audio_timestamp_helper_->base_timestamp() != kNoTimestamp()) { 262 audio_timestamp_helper_->base_timestamp() != kNoTimestamp()) {
192 base::TimeDelta base_timestamp = audio_timestamp_helper_->GetTimestamp(); 263 base::TimeDelta base_timestamp = audio_timestamp_helper_->GetTimestamp();
193 audio_timestamp_helper_.reset( 264 audio_timestamp_helper_.reset(
194 new AudioTimestampHelper(audio_decoder_config.samples_per_second())); 265 new AudioTimestampHelper(audio_decoder_config.samples_per_second()));
195 audio_timestamp_helper_->SetBaseTimestamp(base_timestamp); 266 audio_timestamp_helper_->SetBaseTimestamp(base_timestamp);
196 } else { 267 } else {
197 audio_timestamp_helper_.reset( 268 audio_timestamp_helper_.reset(
198 new AudioTimestampHelper(audio_decoder_config.samples_per_second())); 269 new AudioTimestampHelper(audio_decoder_config.samples_per_second()));
199 } 270 }
200 // Audio config notification. 271 // Audio config notification.
201 last_audio_decoder_config_ = audio_decoder_config; 272 last_audio_decoder_config_ = audio_decoder_config;
202 new_audio_config_cb_.Run(audio_decoder_config); 273 new_audio_config_cb_.Run(audio_decoder_config);
203 } 274 }
204 275
205 return true; 276 return true;
206 } 277 }
207 278
208 } // namespace mp2t 279 } // namespace mp2t
209 } // namespace media 280 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698