| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/filters/ffmpeg_audio_decoder.h" | 5 #include "media/filters/ffmpeg_audio_decoder.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 scoped_refptr<AudioBuffer> output; | 219 scoped_refptr<AudioBuffer> output; |
| 220 | 220 |
| 221 bool config_changed = false; | 221 bool config_changed = false; |
| 222 if (frame_decoded) { | 222 if (frame_decoded) { |
| 223 const int channels = DetermineChannels(av_frame_.get()); | 223 const int channels = DetermineChannels(av_frame_.get()); |
| 224 ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout( | 224 ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout( |
| 225 codec_context_->channel_layout, codec_context_->channels); | 225 codec_context_->channel_layout, codec_context_->channels); |
| 226 | 226 |
| 227 bool is_sample_rate_change = | 227 bool is_sample_rate_change = |
| 228 av_frame_->sample_rate != config_.samples_per_second(); | 228 av_frame_->sample_rate != config_.samples_per_second(); |
| 229 bool is_config_stale = | 229 bool is_config_stale = is_sample_rate_change || |
| 230 is_sample_rate_change || | 230 channels != config_.channels() || |
| 231 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || | 231 av_frame_->format != av_sample_format_; |
| 232 av_frame_->format != av_sample_format_; | |
| 233 | 232 |
| 234 // Only consider channel layout changes for AAC. | 233 // Only consider channel layout changes for AAC. |
| 235 // TODO(tguilbert, dalecurtis): Due to http://crbug.com/600538 we need to | 234 // TODO(tguilbert, dalecurtis): Due to http://crbug.com/600538 we need to |
| 236 // allow channel layout changes for the moment. See if ffmpeg is fixable. | 235 // allow channel layout changes for the moment. See if ffmpeg is fixable. |
| 237 if (config_.codec() == kCodecAAC) | 236 if (config_.codec() == kCodecAAC) |
| 238 is_config_stale |= channel_layout != config_.channel_layout(); | 237 is_config_stale |= channel_layout != config_.channel_layout(); |
| 239 | 238 |
| 240 if (is_config_stale) { | 239 if (is_config_stale) { |
| 241 // Only allow midstream configuration changes for AAC. Sample format is | 240 // Only allow midstream configuration changes for AAC. Sample format is |
| 242 // not expected to change between AAC profiles. | 241 // not expected to change between AAC profiles. |
| 243 if (config_.codec() == kCodecAAC && | 242 if (config_.codec() == kCodecAAC && |
| 244 av_frame_->format == av_sample_format_) { | 243 av_frame_->format == av_sample_format_) { |
| 245 MEDIA_LOG(DEBUG, media_log_) | 244 MEDIA_LOG(DEBUG, media_log_) |
| 246 << " Detected AAC midstream configuration change" | 245 << " Detected AAC midstream configuration change" |
| 247 << " PTS:" << buffer->timestamp().InMicroseconds() | 246 << " PTS:" << buffer->timestamp().InMicroseconds() |
| 248 << " Sample Rate: " << av_frame_->sample_rate << " vs " | 247 << " Sample Rate: " << av_frame_->sample_rate << " vs " |
| 249 << config_.samples_per_second() | 248 << config_.samples_per_second() |
| 250 << ", ChannelLayout: " << channel_layout << " vs " | 249 << ", ChannelLayout: " << channel_layout << " vs " |
| 251 << config_.channel_layout() << ", Channels: " << channels | 250 << config_.channel_layout() << ", Channels: " << channels |
| 252 << " vs " | 251 << " vs " << config_.channels(); |
| 253 << ChannelLayoutToChannelCount(config_.channel_layout()); | |
| 254 config_.Initialize(config_.codec(), config_.sample_format(), | 252 config_.Initialize(config_.codec(), config_.sample_format(), |
| 255 channel_layout, av_frame_->sample_rate, | 253 channel_layout, av_frame_->sample_rate, |
| 256 config_.extra_data(), config_.encryption_scheme(), | 254 config_.extra_data(), config_.encryption_scheme(), |
| 257 config_.seek_preroll(), config_.codec_delay()); | 255 config_.seek_preroll(), config_.codec_delay()); |
| 258 config_changed = true; | 256 config_changed = true; |
| 259 if (is_sample_rate_change) | 257 if (is_sample_rate_change) |
| 260 ResetTimestampState(config_); | 258 ResetTimestampState(config_); |
| 261 } else { | 259 } else { |
| 262 MEDIA_LOG(ERROR, media_log_) | 260 MEDIA_LOG(ERROR, media_log_) |
| 263 << "Unsupported midstream configuration change!" | 261 << "Unsupported midstream configuration change!" |
| 264 << " Sample Rate: " << av_frame_->sample_rate << " vs " | 262 << " Sample Rate: " << av_frame_->sample_rate << " vs " |
| 265 << config_.samples_per_second() << ", Channels: " << channels | 263 << config_.samples_per_second() << ", Channels: " << channels |
| 266 << " vs " << ChannelLayoutToChannelCount(config_.channel_layout()) | 264 << " vs " << config_.channels() |
| 267 << ", Sample Format: " << av_frame_->format << " vs " | 265 << ", Sample Format: " << av_frame_->format << " vs " |
| 268 << av_sample_format_; | 266 << av_sample_format_; |
| 269 // This is an unrecoverable error, so bail out. | 267 // This is an unrecoverable error, so bail out. |
| 270 av_frame_unref(av_frame_.get()); | 268 av_frame_unref(av_frame_.get()); |
| 271 return false; | 269 return false; |
| 272 } | 270 } |
| 273 } | 271 } |
| 274 | 272 |
| 275 // Get the AudioBuffer that the data was decoded into. Adjust the number | 273 // Get the AudioBuffer that the data was decoded into. Adjust the number |
| 276 // of frames, in case fewer than requested were actually decoded. | 274 // of frames, in case fewer than requested were actually decoded. |
| 277 output = reinterpret_cast<AudioBuffer*>( | 275 output = reinterpret_cast<AudioBuffer*>( |
| 278 av_buffer_get_opaque(av_frame_->buf[0])); | 276 av_buffer_get_opaque(av_frame_->buf[0])); |
| 279 | 277 |
| 280 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), | 278 DCHECK_EQ(config_.channels(), output->channel_count()); |
| 281 output->channel_count()); | |
| 282 const int unread_frames = output->frame_count() - av_frame_->nb_samples; | 279 const int unread_frames = output->frame_count() - av_frame_->nb_samples; |
| 283 DCHECK_GE(unread_frames, 0); | 280 DCHECK_GE(unread_frames, 0); |
| 284 if (unread_frames > 0) | 281 if (unread_frames > 0) |
| 285 output->TrimEnd(unread_frames); | 282 output->TrimEnd(unread_frames); |
| 286 av_frame_unref(av_frame_.get()); | 283 av_frame_unref(av_frame_.get()); |
| 287 } | 284 } |
| 288 | 285 |
| 289 // WARNING: |av_frame_| no longer has valid data at this point. | 286 // WARNING: |av_frame_| no longer has valid data at this point. |
| 290 const int decoded_frames = frame_decoded ? output->frame_count() : 0; | 287 const int decoded_frames = frame_decoded ? output->frame_count() : 0; |
| 291 if (IsEndOfStream(result, decoded_frames, buffer)) { | 288 if (IsEndOfStream(result, decoded_frames, buffer)) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 << codec_context_->codec_id; | 333 << codec_context_->codec_id; |
| 337 ReleaseFFmpegResources(); | 334 ReleaseFFmpegResources(); |
| 338 state_ = kUninitialized; | 335 state_ = kUninitialized; |
| 339 return false; | 336 return false; |
| 340 } | 337 } |
| 341 | 338 |
| 342 // Success! | 339 // Success! |
| 343 av_frame_.reset(av_frame_alloc()); | 340 av_frame_.reset(av_frame_alloc()); |
| 344 av_sample_format_ = codec_context_->sample_fmt; | 341 av_sample_format_ = codec_context_->sample_fmt; |
| 345 | 342 |
| 346 if (codec_context_->channels != | 343 if (codec_context_->channels != config.channels()) { |
| 347 ChannelLayoutToChannelCount(config.channel_layout())) { | |
| 348 MEDIA_LOG(ERROR, media_log_) | 344 MEDIA_LOG(ERROR, media_log_) |
| 349 << "Audio configuration specified " | 345 << "Audio configuration specified " << config.channels() |
| 350 << ChannelLayoutToChannelCount(config.channel_layout()) | |
| 351 << " channels, but FFmpeg thinks the file contains " | 346 << " channels, but FFmpeg thinks the file contains " |
| 352 << codec_context_->channels << " channels"; | 347 << codec_context_->channels << " channels"; |
| 353 ReleaseFFmpegResources(); | 348 ReleaseFFmpegResources(); |
| 354 state_ = kUninitialized; | 349 state_ = kUninitialized; |
| 355 return false; | 350 return false; |
| 356 } | 351 } |
| 357 | 352 |
| 358 ResetTimestampState(config); | 353 ResetTimestampState(config); |
| 359 return true; | 354 return true; |
| 360 } | 355 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 // we need to take this into consideration. | 403 // we need to take this into consideration. |
| 409 int buffer_size_in_bytes = av_samples_get_buffer_size( | 404 int buffer_size_in_bytes = av_samples_get_buffer_size( |
| 410 &frame->linesize[0], channels, frame->nb_samples, format, | 405 &frame->linesize[0], channels, frame->nb_samples, format, |
| 411 0 /* align, use ffmpeg default */); | 406 0 /* align, use ffmpeg default */); |
| 412 // Check for errors from av_samples_get_buffer_size(). | 407 // Check for errors from av_samples_get_buffer_size(). |
| 413 if (buffer_size_in_bytes < 0) | 408 if (buffer_size_in_bytes < 0) |
| 414 return buffer_size_in_bytes; | 409 return buffer_size_in_bytes; |
| 415 int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; | 410 int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; |
| 416 DCHECK_GE(frames_required, frame->nb_samples); | 411 DCHECK_GE(frames_required, frame->nb_samples); |
| 417 | 412 |
| 418 ChannelLayout channel_layout = | 413 if (config_.channel_layout() == CHANNEL_LAYOUT_UNSUPPORTED) { |
| 419 ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); | |
| 420 | |
| 421 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { | |
| 422 DLOG(ERROR) << "Unsupported channel layout."; | 414 DLOG(ERROR) << "Unsupported channel layout."; |
| 423 return AVERROR(EINVAL); | 415 return AVERROR(EINVAL); |
| 424 } | 416 } |
| 425 | 417 |
| 426 scoped_refptr<AudioBuffer> buffer = | 418 scoped_refptr<AudioBuffer> buffer = AudioBuffer::CreateBuffer( |
| 427 AudioBuffer::CreateBuffer(sample_format, channel_layout, channels, | 419 sample_format, config_.channel_layout(), channels, s->sample_rate, |
| 428 s->sample_rate, frames_required, pool_); | 420 frames_required, pool_); |
| 429 | 421 |
| 430 // Initialize the data[] and extended_data[] fields to point into the memory | 422 // Initialize the data[] and extended_data[] fields to point into the memory |
| 431 // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved | 423 // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved |
| 432 // audio and equal to |channels| for planar audio. | 424 // audio and equal to |channels| for planar audio. |
| 433 int number_of_planes = buffer->channel_data().size(); | 425 int number_of_planes = buffer->channel_data().size(); |
| 434 if (number_of_planes <= AV_NUM_DATA_POINTERS) { | 426 if (number_of_planes <= AV_NUM_DATA_POINTERS) { |
| 435 DCHECK_EQ(frame->extended_data, frame->data); | 427 DCHECK_EQ(frame->extended_data, frame->data); |
| 436 for (int i = 0; i < number_of_planes; ++i) | 428 for (int i = 0; i < number_of_planes; ++i) |
| 437 frame->data[i] = buffer->channel_data()[i]; | 429 frame->data[i] = buffer->channel_data()[i]; |
| 438 } else { | 430 } else { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 450 // Now create an AVBufferRef for the data just allocated. It will own the | 442 // Now create an AVBufferRef for the data just allocated. It will own the |
| 451 // reference to the AudioBuffer object. | 443 // reference to the AudioBuffer object. |
| 452 AudioBuffer* opaque = buffer.get(); | 444 AudioBuffer* opaque = buffer.get(); |
| 453 opaque->AddRef(); | 445 opaque->AddRef(); |
| 454 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, | 446 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, |
| 455 ReleaseAudioBufferImpl, opaque, 0); | 447 ReleaseAudioBufferImpl, opaque, 0); |
| 456 return 0; | 448 return 0; |
| 457 } | 449 } |
| 458 | 450 |
| 459 } // namespace media | 451 } // namespace media |
| OLD | NEW |