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

Unified Diff: media/renderers/audio_renderer_impl.cc

Issue 2466463005: Support (E)AC3 passthrough
Patch Set: Add unit tests 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 side-by-side diff with in-line comments
Download patch
Index: media/renderers/audio_renderer_impl.cc
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 0d417c405a1fe42d806285600349a74505d2e021..a12cb7fdb2562aa65fa7793400dfc02e2ebd548b 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -24,6 +24,7 @@
#include "media/base/bind_to_current_loop.h"
#include "media/base/channel_mixing_matrix.h"
#include "media/base/demuxer_stream.h"
+#include "media/base/media_client.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/base/renderer_client.h"
@@ -33,6 +34,8 @@
namespace media {
+static const int kMaxFramesPerCompressedAudioBuffer = 4096;
DaleCurtis 2017/06/15 21:46:33 Needs explanation; possibly should be stored in Au
AndyWu 2017/08/02 01:43:41 Done.
+
AudioRendererImpl::AudioRendererImpl(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
media::AudioRendererSink* sink,
@@ -59,6 +62,8 @@ AudioRendererImpl::AudioRendererImpl(
received_end_of_stream_(false),
rendered_end_of_stream_(false),
is_suspending_(false),
+ is_passthrough_(false),
+ last_reported_media_time_(kNoTimestamp),
weak_factory_(this) {
DCHECK(create_audio_decoders_cb_);
// Tests may not have a power monitor.
@@ -179,6 +184,7 @@ void AudioRendererImpl::SetMediaTime(base::TimeDelta time) {
last_render_time_ = stop_rendering_time_ = base::TimeTicks();
first_packet_timestamp_ = kNoTimestamp;
audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate()));
+ last_reported_media_time_ = kNoTimestamp;
}
base::TimeDelta AudioRendererImpl::CurrentMediaTime() {
@@ -194,7 +200,14 @@ base::TimeDelta AudioRendererImpl::CurrentMediaTime() {
current_media_time = audio_clock_->back_timestamp();
}
- return current_media_time;
+ // Clamp current media time to the last reported value, this prevents higher
DaleCurtis 2017/06/15 21:46:33 We already do this in PipelineImpl.
AndyWu 2017/08/02 01:43:41 Hi Chris, do you agree to remove this logic?
chcunningham 2017/08/04 19:26:40 Yep, should be fine. It used to live here, but had
AndyWu 2017/08/04 21:45:52 Thanks for your feedback.
+ // level clients from seeing time go backwards. This may happen when seeking
+ // a passthrough audio stream, since we are unable to trim a compressed audio
+ // buffer.
+ if (last_reported_media_time_ < current_media_time)
+ last_reported_media_time_ = current_media_time;
+
+ return last_reported_media_time_;
}
bool AudioRendererImpl::GetWallClockTimes(
@@ -369,6 +382,10 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
auto output_device_info = sink_->GetOutputDeviceInfo();
const AudioParameters& hw_params = output_device_info.output_params();
+ AudioCodec codec = stream->audio_decoder_config().codec();
+ MediaClient* media_client = GetMediaClient();
DaleCurtis 2017/06/15 21:46:33 if (auto* mc = GetMediaClient()) is_passthrough_
AndyWu 2017/08/02 01:43:41 Done.
+ is_passthrough_ =
+ media_client && media_client->IsSupportedBitstreamAudioCodec(codec);
expecting_config_changes_ = stream->SupportsConfigChanges();
bool use_stream_params = !expecting_config_changes_ || !hw_params.IsValid() ||
@@ -381,7 +398,25 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
use_stream_params = false;
}
- if (use_stream_params) {
+ if (is_passthrough_) {
+ AudioParameters::Format format = AudioParameters::AUDIO_FAKE;
+ if (codec == kCodecAC3) {
+ format = AudioParameters::AUDIO_BITSTREAM_AC3;
+ } else if (codec == kCodecEAC3) {
+ format = AudioParameters::AUDIO_BITSTREAM_EAC3;
+ } else {
+ NOTREACHED();
+ }
+
+ const int buffer_size = kMaxFramesPerCompressedAudioBuffer *
+ stream->audio_decoder_config().bytes_per_frame();
+
+ audio_parameters_.Reset(
+ format, stream->audio_decoder_config().channel_layout(),
+ stream->audio_decoder_config().samples_per_second(),
+ stream->audio_decoder_config().bits_per_channel(), buffer_size);
+ buffer_converter_.reset();
+ } else if (use_stream_params) {
// The actual buffer size is controlled via the size of the AudioBus
// provided to Render(), but we should choose a value here based on hardware
// parameters if possible since it affects the initial buffer size used by
@@ -669,7 +704,19 @@ bool AudioRendererImpl::HandleDecodedBuffer_Locked(
if (buffer->end_of_stream()) {
received_end_of_stream_ = true;
} else {
- if (state_ == kPlaying) {
+ if (buffer->IsBitstreamFormat() && state_ == kPlaying) {
+ if (IsBeforeStartTime(buffer))
+ return true;
+
+ // Adjust the start time since we are unable to trim a compressed audio
+ // buffer.
+ if (buffer->timestamp() < start_timestamp_ &&
DaleCurtis 2017/06/15 21:46:33 I'd just skip this and seek to the first full buff
AndyWu 2017/08/02 01:43:41 Done.
+ (buffer->timestamp() + buffer->duration()) > start_timestamp_) {
+ start_timestamp_ = buffer->timestamp();
+ audio_clock_.reset(new AudioClock(buffer->timestamp(),
+ audio_parameters_.sample_rate()));
+ }
+ } else if (state_ == kPlaying) {
if (IsBeforeStartTime(buffer))
return true;
@@ -768,6 +815,13 @@ void AudioRendererImpl::SetPlaybackRate(double playback_rate) {
base::AutoLock auto_lock(lock_);
+ if (is_passthrough_ && playback_rate != 0 && playback_rate != 1) {
+ MEDIA_LOG(ERROR, media_log_)
DaleCurtis 2017/06/15 21:46:32 WARNING or INFO, no need for ERROR.
AndyWu 2017/08/02 01:43:41 Done.
+ << "Unsupported playback rate when outputing compressed bitstream."
+ << " Playback Rate: " << playback_rate;
+ return;
+ }
+
// We have two cases here:
// Play: current_playback_rate == 0 && playback_rate != 0
// Pause: current_playback_rate != 0 && playback_rate == 0
@@ -799,7 +853,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
int prior_frames_skipped,
AudioBus* audio_bus) {
- const int frames_requested = audio_bus->frames();
+ int frames_requested = audio_bus->frames();
DVLOG(4) << __func__ << " delay:" << delay
<< " prior_frames_skipped:" << prior_frames_skipped
<< " frames_requested:" << frames_requested;
@@ -838,9 +892,13 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
return 0;
}
- // Delay playback by writing silence if we haven't reached the first
- // timestamp yet; this can occur if the video starts before the audio.
- if (algorithm_->frames_buffered() > 0) {
+ if (is_passthrough_ && algorithm_->frames_buffered() > 0) {
+ frames_written += algorithm_->FillBuffer(audio_bus, 0, frames_requested,
chcunningham 2017/06/14 20:03:08 special passthrough logic needs "why" documentatio
DaleCurtis 2017/06/15 21:46:33 FYI, this is going to be wrong in cases where the
AndyWu 2017/08/02 01:43:41 Done.
AndyWu 2017/08/02 01:43:41 Done.
+ playback_rate_);
+ frames_requested = frames_written;
+ } else if (algorithm_->frames_buffered() > 0) {
+ // Delay playback by writing silence if we haven't reached the first
+ // timestamp yet; this can occur if the video starts before the audio.
CHECK_NE(first_packet_timestamp_, kNoTimestamp);
CHECK_GE(first_packet_timestamp_, base::TimeDelta());
const base::TimeDelta play_delay =
« media/filters/audio_renderer_algorithm.cc ('K') | « media/renderers/audio_renderer_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698