1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/decoder_stream_traits.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "media/base/audio_buffer.h"
12 #include "media/base/audio_decoder.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/video_decoder.h"
15 #include "media/base/video_frame.h"
19 // Audio decoder stream traits implementation.
22 std::string DecoderStreamTraits<DemuxerStream::AUDIO>::ToString() {
27 bool DecoderStreamTraits<DemuxerStream::AUDIO>::NeedsBitstreamConversion(
28 DecoderType* decoder) {
29 return decoder->NeedsBitstreamConversion();
33 scoped_refptr<DecoderStreamTraits<DemuxerStream::AUDIO>::OutputType>
34 DecoderStreamTraits<DemuxerStream::AUDIO>::CreateEOSOutput() {
35 return OutputType::CreateEOSBuffer();
38 DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
40 ChannelLayout initial_hw_layout)
41 : media_log_(media_log), initial_hw_layout_(initial_hw_layout) {}
43 DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderConfigType
44 DecoderStreamTraits<DemuxerStream::AUDIO>::GetDecoderConfig(
45 DemuxerStream* stream) {
46 auto config = stream->audio_decoder_config();
47 // Demuxer is not aware of hw layout, so we set it here.
48 config.set_target_output_channel_layout(initial_hw_layout_);
52 void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
53 const StatisticsCB& statistics_cb,
55 stats_.audio_bytes_decoded = bytes_decoded;
56 statistics_cb.Run(stats_);
59 void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
61 const DecoderConfigType& config,
63 CdmContext* cdm_context,
64 const InitCB& init_cb,
65 const OutputCB& output_cb,
66 const DecoderType::WaitingForDecryptionKeyCB&
67 waiting_for_decryption_key_cb) {
68 DCHECK(config.IsValidConfig());
70 if (config_.IsValidConfig() && !config_.Matches(config))
71 OnConfigChanged(config);
74 stats_.audio_decoder_name = decoder->GetDisplayName();
75 decoder->Initialize(config, cdm_context, init_cb, output_cb,
76 waiting_for_decryption_key_cb);
79 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnStreamReset(
80 DemuxerStream* stream) {
82 // Stream is likely being seeked to a new timestamp, so make new validator to
83 // build new timestamp expectations.
84 audio_ts_validator_.reset(
85 new AudioTimestampValidator(stream->audio_decoder_config(), media_log_));
88 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecode(
89 const DecoderBuffer& buffer) {
90 audio_ts_validator_->CheckForTimestampGap(buffer);
93 PostDecodeAction DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecodeDone(
94 const scoped_refptr<OutputType>& buffer) {
95 audio_ts_validator_->RecordOutputDuration(buffer);
96 return PostDecodeAction::DELIVER;
99 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnConfigChanged(
100 const DecoderConfigType& config) {
101 // Reset validator with the latest config. Also ensures that we do not attempt
102 // to match timestamps across config boundaries.
103 audio_ts_validator_.reset(new AudioTimestampValidator(config, media_log_));
106 // Video decoder stream traits implementation.
109 std::string DecoderStreamTraits<DemuxerStream::VIDEO>::ToString() {
114 bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion(
115 DecoderType* decoder) {
116 return decoder->NeedsBitstreamConversion();
120 scoped_refptr<DecoderStreamTraits<DemuxerStream::VIDEO>::OutputType>
121 DecoderStreamTraits<DemuxerStream::VIDEO>::CreateEOSOutput() {
122 return OutputType::CreateEOSFrame();
125 DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderStreamTraits(
127 // Randomly selected number of samples to keep.
128 : keyframe_distance_average_(16) {}
130 DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderConfigType
131 DecoderStreamTraits<DemuxerStream::VIDEO>::GetDecoderConfig(
132 DemuxerStream* stream) {
133 return stream->video_decoder_config();
136 void DecoderStreamTraits<DemuxerStream::VIDEO>::ReportStatistics(
137 const StatisticsCB& statistics_cb,
139 stats_.video_bytes_decoded = bytes_decoded;
141 if (keyframe_distance_average_.count()) {
142 stats_.video_keyframe_distance_average =
143 keyframe_distance_average_.Average();
145 // Before we have enough keyframes to calculate the average distance, we
146 // will assume the average keyframe distance is infinitely large.
147 stats_.video_keyframe_distance_average = base::TimeDelta::Max();
150 statistics_cb.Run(stats_);
153 void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
154 DecoderType* decoder,
155 const DecoderConfigType& config,
157 CdmContext* cdm_context,
158 const InitCB& init_cb,
159 const OutputCB& output_cb,
160 const DecoderType::WaitingForDecryptionKeyCB&
161 waiting_for_decryption_key_cb) {
162 DCHECK(config.IsValidConfig());
163 stats_.video_decoder_name = decoder->GetDisplayName();
164 DVLOG(2) << stats_.video_decoder_name;
165 decoder->Initialize(config, low_delay, cdm_context, init_cb, output_cb,
166 waiting_for_decryption_key_cb);
169 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
170 DemuxerStream* stream) {
172 last_keyframe_timestamp_ = base::TimeDelta();
173 frames_to_drop_.clear();
176 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
177 const DecoderBuffer& buffer) {
178 if (buffer.end_of_stream()) {
179 last_keyframe_timestamp_ = base::TimeDelta();
183 if (buffer.discard_padding().first == kInfiniteDuration)
184 frames_to_drop_.insert(buffer.timestamp());
186 if (!buffer.is_key_frame())
189 base::TimeDelta current_frame_timestamp = buffer.timestamp();
190 if (last_keyframe_timestamp_.is_zero()) {
191 last_keyframe_timestamp_ = current_frame_timestamp;
195 base::TimeDelta frame_distance =
196 current_frame_timestamp - last_keyframe_timestamp_;
197 UMA_HISTOGRAM_MEDIUM_TIMES("Media.Video.KeyFrameDistance", frame_distance);
198 last_keyframe_timestamp_ = current_frame_timestamp;
199 keyframe_distance_average_.AddSample(frame_distance);
202 PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
203 const scoped_refptr<OutputType>& buffer) {
204 auto it = frames_to_drop_.find(buffer->timestamp());
205 if (it != frames_to_drop_.end()) {
206 // We erase from the beginning onward to our target frame since frames
207 // should be returned in presentation order. It's possible to accumulate
208 // entries in this queue if playback begins at a non-keyframe; those frames
209 // may never be returned from the decoder.
210 frames_to_drop_.erase(frames_to_drop_.begin(), it + 1);
211 return PostDecodeAction::DROP;
214 return PostDecodeAction::DELIVER;