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

Side by Side Diff: media/filters/ffmpeg_audio_decoder.cc

Issue 2752323002: Support Opus Ambisonics playback (Closed)
Patch Set: another fix for unreliable ffmpeg channels vs layout Created 3 years, 6 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
« no previous file with comments | « media/ffmpeg/ffmpeg_common_unittest.cc ('k') | media/formats/webm/webm_audio_client.cc » ('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 (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 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 scoped_refptr<AudioBuffer> output; 225 scoped_refptr<AudioBuffer> output;
226 226
227 bool config_changed = false; 227 bool config_changed = false;
228 if (frame_decoded) { 228 if (frame_decoded) {
229 const int channels = DetermineChannels(av_frame_.get()); 229 const int channels = DetermineChannels(av_frame_.get());
230 ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout( 230 ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout(
231 codec_context_->channel_layout, codec_context_->channels); 231 codec_context_->channel_layout, codec_context_->channels);
232 232
233 bool is_sample_rate_change = 233 bool is_sample_rate_change =
234 av_frame_->sample_rate != config_.samples_per_second(); 234 av_frame_->sample_rate != config_.samples_per_second();
235 bool is_config_stale = 235 bool is_config_stale = is_sample_rate_change ||
236 is_sample_rate_change || 236 channels != config_.channels() ||
237 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || 237 av_frame_->format != av_sample_format_;
238 av_frame_->format != av_sample_format_;
239 238
240 // Only consider channel layout changes for AAC. 239 // Only consider channel layout changes for AAC.
241 // TODO(tguilbert, dalecurtis): Due to http://crbug.com/600538 we need to 240 // TODO(tguilbert, dalecurtis): Due to http://crbug.com/600538 we need to
242 // allow channel layout changes for the moment. See if ffmpeg is fixable. 241 // allow channel layout changes for the moment. See if ffmpeg is fixable.
243 if (config_.codec() == kCodecAAC) 242 if (config_.codec() == kCodecAAC)
244 is_config_stale |= channel_layout != config_.channel_layout(); 243 is_config_stale |= channel_layout != config_.channel_layout();
245 244
246 if (is_config_stale) { 245 if (is_config_stale) {
247 // Only allow midstream configuration changes for AAC. Sample format is 246 // Only allow midstream configuration changes for AAC. Sample format is
248 // not expected to change between AAC profiles. 247 // not expected to change between AAC profiles.
249 if (config_.codec() == kCodecAAC && 248 if (config_.codec() == kCodecAAC &&
250 av_frame_->format == av_sample_format_) { 249 av_frame_->format == av_sample_format_) {
251 MEDIA_LOG(DEBUG, media_log_) 250 MEDIA_LOG(DEBUG, media_log_)
252 << " Detected AAC midstream configuration change" 251 << " Detected AAC midstream configuration change"
253 << " PTS:" << buffer->timestamp().InMicroseconds() 252 << " PTS:" << buffer->timestamp().InMicroseconds()
254 << " Sample Rate: " << av_frame_->sample_rate << " vs " 253 << " Sample Rate: " << av_frame_->sample_rate << " vs "
255 << config_.samples_per_second() 254 << config_.samples_per_second()
256 << ", ChannelLayout: " << channel_layout << " vs " 255 << ", ChannelLayout: " << channel_layout << " vs "
257 << config_.channel_layout() << ", Channels: " << channels 256 << config_.channel_layout() << ", Channels: " << channels
258 << " vs " 257 << " vs " << config_.channels();
259 << ChannelLayoutToChannelCount(config_.channel_layout());
260 config_.Initialize(config_.codec(), config_.sample_format(), 258 config_.Initialize(config_.codec(), config_.sample_format(),
261 channel_layout, av_frame_->sample_rate, 259 channel_layout, av_frame_->sample_rate,
262 config_.extra_data(), config_.encryption_scheme(), 260 config_.extra_data(), config_.encryption_scheme(),
263 config_.seek_preroll(), config_.codec_delay()); 261 config_.seek_preroll(), config_.codec_delay());
264 config_changed = true; 262 config_changed = true;
265 if (is_sample_rate_change) 263 if (is_sample_rate_change)
266 ResetTimestampState(config_); 264 ResetTimestampState(config_);
267 } else { 265 } else {
268 MEDIA_LOG(ERROR, media_log_) 266 MEDIA_LOG(ERROR, media_log_)
269 << "Unsupported midstream configuration change!" 267 << "Unsupported midstream configuration change!"
270 << " Sample Rate: " << av_frame_->sample_rate << " vs " 268 << " Sample Rate: " << av_frame_->sample_rate << " vs "
271 << config_.samples_per_second() << ", Channels: " << channels 269 << config_.samples_per_second() << ", Channels: " << channels
272 << " vs " << ChannelLayoutToChannelCount(config_.channel_layout()) 270 << " vs " << config_.channels()
273 << ", Sample Format: " << av_frame_->format << " vs " 271 << ", Sample Format: " << av_frame_->format << " vs "
274 << av_sample_format_; 272 << av_sample_format_;
275 // This is an unrecoverable error, so bail out. 273 // This is an unrecoverable error, so bail out.
276 av_frame_unref(av_frame_.get()); 274 av_frame_unref(av_frame_.get());
277 return false; 275 return false;
278 } 276 }
279 } 277 }
280 278
281 // Get the AudioBuffer that the data was decoded into. Adjust the number 279 // Get the AudioBuffer that the data was decoded into. Adjust the number
282 // of frames, in case fewer than requested were actually decoded. 280 // of frames, in case fewer than requested were actually decoded.
283 output = reinterpret_cast<AudioBuffer*>( 281 output = reinterpret_cast<AudioBuffer*>(
284 av_buffer_get_opaque(av_frame_->buf[0])); 282 av_buffer_get_opaque(av_frame_->buf[0]));
285 283
286 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), 284 DCHECK_EQ(config_.channels(), output->channel_count());
287 output->channel_count());
288 const int unread_frames = output->frame_count() - av_frame_->nb_samples; 285 const int unread_frames = output->frame_count() - av_frame_->nb_samples;
289 DCHECK_GE(unread_frames, 0); 286 DCHECK_GE(unread_frames, 0);
290 if (unread_frames > 0) 287 if (unread_frames > 0)
291 output->TrimEnd(unread_frames); 288 output->TrimEnd(unread_frames);
292 av_frame_unref(av_frame_.get()); 289 av_frame_unref(av_frame_.get());
293 } 290 }
294 291
295 // WARNING: |av_frame_| no longer has valid data at this point. 292 // WARNING: |av_frame_| no longer has valid data at this point.
296 const int decoded_frames = frame_decoded ? output->frame_count() : 0; 293 const int decoded_frames = frame_decoded ? output->frame_count() : 0;
297 if (IsEndOfStream(result, decoded_frames, buffer)) { 294 if (IsEndOfStream(result, decoded_frames, buffer)) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 << codec_context_->codec_id; 339 << codec_context_->codec_id;
343 ReleaseFFmpegResources(); 340 ReleaseFFmpegResources();
344 state_ = kUninitialized; 341 state_ = kUninitialized;
345 return false; 342 return false;
346 } 343 }
347 344
348 // Success! 345 // Success!
349 av_frame_.reset(av_frame_alloc()); 346 av_frame_.reset(av_frame_alloc());
350 av_sample_format_ = codec_context_->sample_fmt; 347 av_sample_format_ = codec_context_->sample_fmt;
351 348
352 if (codec_context_->channels != 349 if (codec_context_->channels != config.channels()) {
353 ChannelLayoutToChannelCount(config.channel_layout())) {
354 MEDIA_LOG(ERROR, media_log_) 350 MEDIA_LOG(ERROR, media_log_)
355 << "Audio configuration specified " 351 << "Audio configuration specified " << config.channels()
356 << ChannelLayoutToChannelCount(config.channel_layout())
357 << " channels, but FFmpeg thinks the file contains " 352 << " channels, but FFmpeg thinks the file contains "
358 << codec_context_->channels << " channels"; 353 << codec_context_->channels << " channels";
359 ReleaseFFmpegResources(); 354 ReleaseFFmpegResources();
360 state_ = kUninitialized; 355 state_ = kUninitialized;
361 return false; 356 return false;
362 } 357 }
363 358
364 ResetTimestampState(config); 359 ResetTimestampState(config);
365 return true; 360 return true;
366 } 361 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 int buffer_size_in_bytes = av_samples_get_buffer_size( 410 int buffer_size_in_bytes = av_samples_get_buffer_size(
416 &frame->linesize[0], channels, frame->nb_samples, format, 411 &frame->linesize[0], channels, frame->nb_samples, format,
417 0 /* align, use ffmpeg default */); 412 0 /* align, use ffmpeg default */);
418 // Check for errors from av_samples_get_buffer_size(). 413 // Check for errors from av_samples_get_buffer_size().
419 if (buffer_size_in_bytes < 0) 414 if (buffer_size_in_bytes < 0)
420 return buffer_size_in_bytes; 415 return buffer_size_in_bytes;
421 int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; 416 int frames_required = buffer_size_in_bytes / bytes_per_channel / channels;
422 DCHECK_GE(frames_required, frame->nb_samples); 417 DCHECK_GE(frames_required, frame->nb_samples);
423 418
424 ChannelLayout channel_layout = 419 ChannelLayout channel_layout =
425 ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); 420 config_.channel_layout() == CHANNEL_LAYOUT_DISCRETE
421 ? CHANNEL_LAYOUT_DISCRETE
422 : ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels);
426 423
427 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { 424 if (config_.channel_layout() == CHANNEL_LAYOUT_UNSUPPORTED) {
428 DLOG(ERROR) << "Unsupported channel layout."; 425 DLOG(ERROR) << "Unsupported channel layout.";
429 return AVERROR(EINVAL); 426 return AVERROR(EINVAL);
430 } 427 }
431 428
432 scoped_refptr<AudioBuffer> buffer = 429 scoped_refptr<AudioBuffer> buffer =
433 AudioBuffer::CreateBuffer(sample_format, channel_layout, channels, 430 AudioBuffer::CreateBuffer(sample_format, channel_layout, channels,
434 s->sample_rate, frames_required, pool_); 431 s->sample_rate, frames_required, pool_);
435 432
436 // Initialize the data[] and extended_data[] fields to point into the memory 433 // Initialize the data[] and extended_data[] fields to point into the memory
437 // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved 434 // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved
(...skipping 18 matching lines...) Expand all
456 // Now create an AVBufferRef for the data just allocated. It will own the 453 // Now create an AVBufferRef for the data just allocated. It will own the
457 // reference to the AudioBuffer object. 454 // reference to the AudioBuffer object.
458 AudioBuffer* opaque = buffer.get(); 455 AudioBuffer* opaque = buffer.get();
459 opaque->AddRef(); 456 opaque->AddRef();
460 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, 457 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes,
461 ReleaseAudioBufferImpl, opaque, 0); 458 ReleaseAudioBufferImpl, opaque, 0);
462 return 0; 459 return 0;
463 } 460 }
464 461
465 } // namespace media 462 } // namespace media
OLDNEW
« no previous file with comments | « media/ffmpeg/ffmpeg_common_unittest.cc ('k') | media/formats/webm/webm_audio_client.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698