OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "webkit/renderer/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h" | 5 #include "media/cdm/ppapi/ffmpeg_cdm_audio_decoder.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "media/base/audio_bus.h" | 10 #include "media/base/audio_bus.h" |
11 #include "media/base/audio_timestamp_helper.h" | 11 #include "media/base/audio_timestamp_helper.h" |
12 #include "media/base/buffers.h" | 12 #include "media/base/buffers.h" |
13 #include "media/base/data_buffer.h" | 13 #include "media/base/data_buffer.h" |
14 #include "media/base/limits.h" | 14 #include "media/base/limits.h" |
15 #include "webkit/renderer/media/crypto/ppapi/cdm/content_decryption_module.h" | |
16 | 15 |
17 // Include FFmpeg header files. | 16 // Include FFmpeg header files. |
18 extern "C" { | 17 extern "C" { |
19 // Temporarily disable possible loss of data warning. | 18 // Temporarily disable possible loss of data warning. |
20 MSVC_PUSH_DISABLE_WARNING(4244); | 19 MSVC_PUSH_DISABLE_WARNING(4244); |
21 #include <libavcodec/avcodec.h> | 20 #include <libavcodec/avcodec.h> |
22 MSVC_POP_WARNING(); | 21 MSVC_POP_WARNING(); |
23 } // extern "C" | 22 } // extern "C" |
24 | 23 |
25 namespace webkit_media { | 24 namespace media { |
26 | 25 |
27 // Maximum number of channels with defined layout in src/media. | 26 // Maximum number of channels with defined layout in src/media. |
28 static const int kMaxChannels = 8; | 27 static const int kMaxChannels = 8; |
29 | 28 |
30 static AVCodecID CdmAudioCodecToCodecID( | 29 static AVCodecID CdmAudioCodecToCodecID( |
31 cdm::AudioDecoderConfig::AudioCodec audio_codec) { | 30 cdm::AudioDecoderConfig::AudioCodec audio_codec) { |
32 switch (audio_codec) { | 31 switch (audio_codec) { |
33 case cdm::AudioDecoderConfig::kCodecVorbis: | 32 case cdm::AudioDecoderConfig::kCodecVorbis: |
34 return AV_CODEC_ID_VORBIS; | 33 return AV_CODEC_ID_VORBIS; |
35 case cdm::AudioDecoderConfig::kCodecAac: | 34 case cdm::AudioDecoderConfig::kCodecAac: |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 FFmpegCdmAudioDecoder::FFmpegCdmAudioDecoder(cdm::Host* host) | 82 FFmpegCdmAudioDecoder::FFmpegCdmAudioDecoder(cdm::Host* host) |
84 : is_initialized_(false), | 83 : is_initialized_(false), |
85 host_(host), | 84 host_(host), |
86 codec_context_(NULL), | 85 codec_context_(NULL), |
87 av_frame_(NULL), | 86 av_frame_(NULL), |
88 bits_per_channel_(0), | 87 bits_per_channel_(0), |
89 samples_per_second_(0), | 88 samples_per_second_(0), |
90 channels_(0), | 89 channels_(0), |
91 av_sample_format_(0), | 90 av_sample_format_(0), |
92 bytes_per_frame_(0), | 91 bytes_per_frame_(0), |
93 last_input_timestamp_(media::kNoTimestamp()), | 92 last_input_timestamp_(kNoTimestamp()), |
94 output_bytes_to_drop_(0) { | 93 output_bytes_to_drop_(0) { |
95 } | 94 } |
96 | 95 |
97 FFmpegCdmAudioDecoder::~FFmpegCdmAudioDecoder() { | 96 FFmpegCdmAudioDecoder::~FFmpegCdmAudioDecoder() { |
98 ReleaseFFmpegResources(); | 97 ReleaseFFmpegResources(); |
99 } | 98 } |
100 | 99 |
101 bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) { | 100 bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) { |
102 DVLOG(1) << "Initialize()"; | 101 DVLOG(1) << "Initialize()"; |
103 | 102 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 // Some codecs will only output float data, so we need to convert to integer | 135 // Some codecs will only output float data, so we need to convert to integer |
137 // before returning the decoded buffer. | 136 // before returning the decoded buffer. |
138 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP || | 137 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP || |
139 codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { | 138 codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { |
140 // Preallocate the AudioBus for float conversions. We can treat interleaved | 139 // Preallocate the AudioBus for float conversions. We can treat interleaved |
141 // float data as a single planar channel since our output is expected in an | 140 // float data as a single planar channel since our output is expected in an |
142 // interleaved format anyways. | 141 // interleaved format anyways. |
143 int channels = codec_context_->channels; | 142 int channels = codec_context_->channels; |
144 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) | 143 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) |
145 channels = 1; | 144 channels = 1; |
146 converter_bus_ = media::AudioBus::CreateWrapper(channels); | 145 converter_bus_ = AudioBus::CreateWrapper(channels); |
147 } | 146 } |
148 | 147 |
149 // Success! | 148 // Success! |
150 av_frame_ = avcodec_alloc_frame(); | 149 av_frame_ = avcodec_alloc_frame(); |
151 bits_per_channel_ = config.bits_per_channel; | 150 bits_per_channel_ = config.bits_per_channel; |
152 samples_per_second_ = config.samples_per_second; | 151 samples_per_second_ = config.samples_per_second; |
153 bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8; | 152 bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8; |
154 output_timestamp_helper_.reset( | 153 output_timestamp_helper_.reset( |
155 new media::AudioTimestampHelper(config.samples_per_second)); | 154 new AudioTimestampHelper(config.samples_per_second)); |
156 serialized_audio_frames_.reserve(bytes_per_frame_ * samples_per_second_); | 155 serialized_audio_frames_.reserve(bytes_per_frame_ * samples_per_second_); |
157 is_initialized_ = true; | 156 is_initialized_ = true; |
158 | 157 |
159 // Store initial values to guard against midstream configuration changes. | 158 // Store initial values to guard against midstream configuration changes. |
160 channels_ = codec_context_->channels; | 159 channels_ = codec_context_->channels; |
161 av_sample_format_ = codec_context_->sample_fmt; | 160 av_sample_format_ = codec_context_->sample_fmt; |
162 | 161 |
163 return true; | 162 return true; |
164 } | 163 } |
165 | 164 |
(...skipping 10 matching lines...) Expand all Loading... |
176 ResetTimestampState(); | 175 ResetTimestampState(); |
177 } | 176 } |
178 | 177 |
179 // static | 178 // static |
180 bool FFmpegCdmAudioDecoder::IsValidConfig( | 179 bool FFmpegCdmAudioDecoder::IsValidConfig( |
181 const cdm::AudioDecoderConfig& config) { | 180 const cdm::AudioDecoderConfig& config) { |
182 return config.codec != cdm::AudioDecoderConfig::kUnknownAudioCodec && | 181 return config.codec != cdm::AudioDecoderConfig::kUnknownAudioCodec && |
183 config.channel_count > 0 && | 182 config.channel_count > 0 && |
184 config.channel_count <= kMaxChannels && | 183 config.channel_count <= kMaxChannels && |
185 config.bits_per_channel > 0 && | 184 config.bits_per_channel > 0 && |
186 config.bits_per_channel <= media::limits::kMaxBitsPerSample && | 185 config.bits_per_channel <= limits::kMaxBitsPerSample && |
187 config.samples_per_second > 0 && | 186 config.samples_per_second > 0 && |
188 config.samples_per_second <= media::limits::kMaxSampleRate; | 187 config.samples_per_second <= limits::kMaxSampleRate; |
189 } | 188 } |
190 | 189 |
191 cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( | 190 cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( |
192 const uint8_t* compressed_buffer, | 191 const uint8_t* compressed_buffer, |
193 int32_t compressed_buffer_size, | 192 int32_t compressed_buffer_size, |
194 int64_t input_timestamp, | 193 int64_t input_timestamp, |
195 cdm::AudioFrames* decoded_frames) { | 194 cdm::AudioFrames* decoded_frames) { |
196 DVLOG(1) << "DecodeBuffer()"; | 195 DVLOG(1) << "DecodeBuffer()"; |
197 const bool is_end_of_stream = !compressed_buffer; | 196 const bool is_end_of_stream = !compressed_buffer; |
198 base::TimeDelta timestamp = | 197 base::TimeDelta timestamp = |
199 base::TimeDelta::FromMicroseconds(input_timestamp); | 198 base::TimeDelta::FromMicroseconds(input_timestamp); |
200 | 199 |
201 bool is_vorbis = codec_context_->codec_id == AV_CODEC_ID_VORBIS; | 200 bool is_vorbis = codec_context_->codec_id == AV_CODEC_ID_VORBIS; |
202 if (!is_end_of_stream) { | 201 if (!is_end_of_stream) { |
203 if (last_input_timestamp_ == media::kNoTimestamp()) { | 202 if (last_input_timestamp_ == kNoTimestamp()) { |
204 if (is_vorbis && timestamp < base::TimeDelta()) { | 203 if (is_vorbis && timestamp < base::TimeDelta()) { |
205 // Dropping frames for negative timestamps as outlined in section A.2 | 204 // Dropping frames for negative timestamps as outlined in section A.2 |
206 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 205 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
207 int frames_to_drop = floor( | 206 int frames_to_drop = floor( |
208 0.5 + -timestamp.InSecondsF() * samples_per_second_); | 207 0.5 + -timestamp.InSecondsF() * samples_per_second_); |
209 output_bytes_to_drop_ = bytes_per_frame_ * frames_to_drop; | 208 output_bytes_to_drop_ = bytes_per_frame_ * frames_to_drop; |
210 } else { | 209 } else { |
211 last_input_timestamp_ = timestamp; | 210 last_input_timestamp_ = timestamp; |
212 } | 211 } |
213 } else if (timestamp != media::kNoTimestamp()) { | 212 } else if (timestamp != kNoTimestamp()) { |
214 if (timestamp < last_input_timestamp_) { | 213 if (timestamp < last_input_timestamp_) { |
215 base::TimeDelta diff = timestamp - last_input_timestamp_; | 214 base::TimeDelta diff = timestamp - last_input_timestamp_; |
216 DVLOG(1) << "Input timestamps are not monotonically increasing! " | 215 DVLOG(1) << "Input timestamps are not monotonically increasing! " |
217 << " ts " << timestamp.InMicroseconds() << " us" | 216 << " ts " << timestamp.InMicroseconds() << " us" |
218 << " diff " << diff.InMicroseconds() << " us"; | 217 << " diff " << diff.InMicroseconds() << " us"; |
219 return cdm::kDecodeError; | 218 return cdm::kDecodeError; |
220 } | 219 } |
221 | 220 |
222 last_input_timestamp_ = timestamp; | 221 last_input_timestamp_ = timestamp; |
223 } | 222 } |
(...skipping 29 matching lines...) Expand all Loading... |
253 << compressed_buffer_size << " bytes"; | 252 << compressed_buffer_size << " bytes"; |
254 | 253 |
255 return cdm::kDecodeError; | 254 return cdm::kDecodeError; |
256 } | 255 } |
257 | 256 |
258 // Update packet size and data pointer in case we need to call the decoder | 257 // Update packet size and data pointer in case we need to call the decoder |
259 // with the remaining bytes from this packet. | 258 // with the remaining bytes from this packet. |
260 packet.size -= result; | 259 packet.size -= result; |
261 packet.data += result; | 260 packet.data += result; |
262 | 261 |
263 if (output_timestamp_helper_->base_timestamp() == media::kNoTimestamp() && | 262 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
264 !is_end_of_stream) { | 263 !is_end_of_stream) { |
265 DCHECK(timestamp != media::kNoTimestamp()); | 264 DCHECK(timestamp != kNoTimestamp()); |
266 if (output_bytes_to_drop_ > 0) { | 265 if (output_bytes_to_drop_ > 0) { |
267 // Currently Vorbis is the only codec that causes us to drop samples. | 266 // Currently Vorbis is the only codec that causes us to drop samples. |
268 // If we have to drop samples it always means the timeline starts at 0. | 267 // If we have to drop samples it always means the timeline starts at 0. |
269 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); | 268 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); |
270 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | 269 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
271 } else { | 270 } else { |
272 output_timestamp_helper_->SetBaseTimestamp(timestamp); | 271 output_timestamp_helper_->SetBaseTimestamp(timestamp); |
273 } | 272 } |
274 } | 273 } |
275 | 274 |
(...skipping 28 matching lines...) Expand all Loading... |
304 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { | 303 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { |
305 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) | 304 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) |
306 << "Decoder didn't output full frames"; | 305 << "Decoder didn't output full frames"; |
307 | 306 |
308 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); | 307 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); |
309 start_sample = dropped_size / bytes_per_frame_; | 308 start_sample = dropped_size / bytes_per_frame_; |
310 decoded_audio_size -= dropped_size; | 309 decoded_audio_size -= dropped_size; |
311 output_bytes_to_drop_ -= dropped_size; | 310 output_bytes_to_drop_ -= dropped_size; |
312 } | 311 } |
313 | 312 |
314 scoped_refptr<media::DataBuffer> output; | 313 scoped_refptr<DataBuffer> output; |
315 if (decoded_audio_size > 0) { | 314 if (decoded_audio_size > 0) { |
316 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) | 315 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) |
317 << "Decoder didn't output full frames"; | 316 << "Decoder didn't output full frames"; |
318 | 317 |
319 // Convert float data using an AudioBus. | 318 // Convert float data using an AudioBus. |
320 if (converter_bus_) { | 319 if (converter_bus_) { |
321 // Setup the AudioBus as a wrapper of the AVFrame data and then use | 320 // Setup the AudioBus as a wrapper of the AVFrame data and then use |
322 // AudioBus::ToInterleaved() to convert the data as necessary. | 321 // AudioBus::ToInterleaved() to convert the data as necessary. |
323 int skip_frames = start_sample; | 322 int skip_frames = start_sample; |
324 int total_frames = av_frame_->nb_samples; | 323 int total_frames = av_frame_->nb_samples; |
325 int frames_to_interleave = decoded_audio_size / bytes_per_frame_; | 324 int frames_to_interleave = decoded_audio_size / bytes_per_frame_; |
326 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { | 325 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { |
327 DCHECK_EQ(converter_bus_->channels(), 1); | 326 DCHECK_EQ(converter_bus_->channels(), 1); |
328 total_frames *= codec_context_->channels; | 327 total_frames *= codec_context_->channels; |
329 skip_frames *= codec_context_->channels; | 328 skip_frames *= codec_context_->channels; |
330 frames_to_interleave *= codec_context_->channels; | 329 frames_to_interleave *= codec_context_->channels; |
331 } | 330 } |
332 | 331 |
333 converter_bus_->set_frames(total_frames); | 332 converter_bus_->set_frames(total_frames); |
334 for (int i = 0; i < converter_bus_->channels(); ++i) { | 333 for (int i = 0; i < converter_bus_->channels(); ++i) { |
335 converter_bus_->SetChannelData(i, reinterpret_cast<float*>( | 334 converter_bus_->SetChannelData(i, reinterpret_cast<float*>( |
336 av_frame_->extended_data[i])); | 335 av_frame_->extended_data[i])); |
337 } | 336 } |
338 | 337 |
339 output = new media::DataBuffer(decoded_audio_size); | 338 output = new DataBuffer(decoded_audio_size); |
340 output->set_data_size(decoded_audio_size); | 339 output->set_data_size(decoded_audio_size); |
341 | 340 |
342 DCHECK_EQ(frames_to_interleave, converter_bus_->frames() - skip_frames); | 341 DCHECK_EQ(frames_to_interleave, converter_bus_->frames() - skip_frames); |
343 converter_bus_->ToInterleavedPartial( | 342 converter_bus_->ToInterleavedPartial( |
344 skip_frames, frames_to_interleave, bits_per_channel_ / 8, | 343 skip_frames, frames_to_interleave, bits_per_channel_ / 8, |
345 output->writable_data()); | 344 output->writable_data()); |
346 } else { | 345 } else { |
347 output = media::DataBuffer::CopyFrom( | 346 output = DataBuffer::CopyFrom( |
348 av_frame_->extended_data[0] + start_sample * bytes_per_frame_, | 347 av_frame_->extended_data[0] + start_sample * bytes_per_frame_, |
349 decoded_audio_size); | 348 decoded_audio_size); |
350 } | 349 } |
351 | 350 |
352 base::TimeDelta output_timestamp = | 351 base::TimeDelta output_timestamp = |
353 output_timestamp_helper_->GetTimestamp(); | 352 output_timestamp_helper_->GetTimestamp(); |
354 output_timestamp_helper_->AddFrames(decoded_audio_size / | 353 output_timestamp_helper_->AddFrames(decoded_audio_size / |
355 bytes_per_frame_); | 354 bytes_per_frame_); |
356 | 355 |
357 // Serialize the audio samples into |serialized_audio_frames_|. | 356 // Serialize the audio samples into |serialized_audio_frames_|. |
(...skipping 19 matching lines...) Expand all Loading... |
377 decoded_frames->FrameBuffer()->SetSize(serialized_audio_frames_.size()); | 376 decoded_frames->FrameBuffer()->SetSize(serialized_audio_frames_.size()); |
378 serialized_audio_frames_.clear(); | 377 serialized_audio_frames_.clear(); |
379 | 378 |
380 return cdm::kSuccess; | 379 return cdm::kSuccess; |
381 } | 380 } |
382 | 381 |
383 return cdm::kNeedMoreData; | 382 return cdm::kNeedMoreData; |
384 } | 383 } |
385 | 384 |
386 void FFmpegCdmAudioDecoder::ResetTimestampState() { | 385 void FFmpegCdmAudioDecoder::ResetTimestampState() { |
387 output_timestamp_helper_->SetBaseTimestamp(media::kNoTimestamp()); | 386 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
388 last_input_timestamp_ = media::kNoTimestamp(); | 387 last_input_timestamp_ = kNoTimestamp(); |
389 output_bytes_to_drop_ = 0; | 388 output_bytes_to_drop_ = 0; |
390 } | 389 } |
391 | 390 |
392 void FFmpegCdmAudioDecoder::ReleaseFFmpegResources() { | 391 void FFmpegCdmAudioDecoder::ReleaseFFmpegResources() { |
393 DVLOG(1) << "ReleaseFFmpegResources()"; | 392 DVLOG(1) << "ReleaseFFmpegResources()"; |
394 | 393 |
395 if (codec_context_) { | 394 if (codec_context_) { |
396 av_free(codec_context_->extradata); | 395 av_free(codec_context_->extradata); |
397 avcodec_close(codec_context_); | 396 avcodec_close(codec_context_); |
398 av_free(codec_context_); | 397 av_free(codec_context_); |
399 codec_context_ = NULL; | 398 codec_context_ = NULL; |
400 } | 399 } |
401 if (av_frame_) { | 400 if (av_frame_) { |
402 av_free(av_frame_); | 401 av_free(av_frame_); |
403 av_frame_ = NULL; | 402 av_frame_ = NULL; |
404 } | 403 } |
405 } | 404 } |
406 | 405 |
407 void FFmpegCdmAudioDecoder::SerializeInt64(int64 value) { | 406 void FFmpegCdmAudioDecoder::SerializeInt64(int64 value) { |
408 int previous_size = serialized_audio_frames_.size(); | 407 int previous_size = serialized_audio_frames_.size(); |
409 serialized_audio_frames_.resize(previous_size + sizeof(value)); | 408 serialized_audio_frames_.resize(previous_size + sizeof(value)); |
410 memcpy(&serialized_audio_frames_[0] + previous_size, &value, sizeof(value)); | 409 memcpy(&serialized_audio_frames_[0] + previous_size, &value, sizeof(value)); |
411 } | 410 } |
412 | 411 |
413 } // namespace webkit_media | 412 } // namespace media |
OLD | NEW |