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 = |