1 // Copyright 2014 The Chromium Authors
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"
10 #include "base/logging.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "media/base/audio_buffer.h"
13 #include "media/base/audio_decoder.h"
14 #include "media/base/audio_decoder_config.h"
15 #include "media/base/video_decoder.h"
16 #include "media/base/video_frame.h"
20 // Audio decoder stream traits implementation.
23 std::string DecoderStreamTraits<DemuxerStream::AUDIO>::ToString() {
28 bool DecoderStreamTraits<DemuxerStream::AUDIO>::NeedsBitstreamConversion(
29 DecoderType* decoder) {
30 return decoder->NeedsBitstreamConversion();
34 scoped_refptr<DecoderStreamTraits<DemuxerStream::AUDIO>::OutputType>
35 DecoderStreamTraits<DemuxerStream::AUDIO>::CreateEOSOutput() {
36 return OutputType::CreateEOSBuffer();
39 void DecoderStreamTraits<DemuxerStream::AUDIO>::SetIsPlatformDecoder(
40 bool is_platform_decoder) {
41 stats_.audio_pipeline_info.is_platform_decoder = is_platform_decoder;
44 void DecoderStreamTraits<DemuxerStream::AUDIO>::SetIsDecryptingDemuxerStream(
46 stats_.audio_pipeline_info.has_decrypting_demuxer_stream = is_dds;
49 void DecoderStreamTraits<DemuxerStream::AUDIO>::SetEncryptionType(
50 EncryptionType encryption_type) {
51 stats_.audio_pipeline_info.encryption_type = encryption_type;
54 DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
56 ChannelLayout initial_hw_layout,
57 SampleFormat initial_hw_sample_format)
58 : media_log_(media_log),
59 initial_hw_layout_(initial_hw_layout),
60 initial_hw_sample_format_(initial_hw_sample_format) {
61 weak_this_ = weak_factory_.GetWeakPtr();
64 DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderConfigType
65 DecoderStreamTraits<DemuxerStream::AUDIO>::GetDecoderConfig(
66 DemuxerStream* stream) {
67 auto config = stream->audio_decoder_config();
68 // Demuxer is not aware of hw layout, so we set it here.
69 config.set_target_output_channel_layout(initial_hw_layout_);
70 config.set_target_output_sample_format(initial_hw_sample_format_);
74 void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
75 const StatisticsCB& statistics_cb,
77 stats_.audio_bytes_decoded = bytes_decoded;
78 statistics_cb.Run(stats_);
81 void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
83 const DecoderConfigType& config,
85 CdmContext* cdm_context,
87 const OutputCB& output_cb,
88 const WaitingCB& waiting_cb) {
89 DCHECK(config.IsValidConfig());
91 if (config_.IsValidConfig() && !config_.Matches(config))
92 OnConfigChanged(config);
95 stats_.audio_pipeline_info.decoder_type = AudioDecoderType::kUnknown;
96 // Both |this| and |decoder| are owned by a DecoderSelector and will stay
97 // alive at least until |init_cb| is finished executing.
101 &DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecoderInitialized,
102 weak_this_, base::Unretained(decoder), std::move(init_cb)),
103 output_cb, waiting_cb);
106 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecoderInitialized(
107 DecoderType* decoder,
109 DecoderStatus result) {
111 stats_.audio_pipeline_info.decoder_type = decoder->GetDecoderType();
112 std::move(cb).Run(result);
115 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnStreamReset(
116 DemuxerStream* stream) {
118 // Stream is likely being seeked to a new timestamp, so make new validator to
119 // build new timestamp expectations.
120 audio_ts_validator_ = std::make_unique<AudioTimestampValidator>(
121 stream->audio_decoder_config(), media_log_);
124 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecode(
125 const DecoderBuffer& buffer) {
126 audio_ts_validator_->CheckForTimestampGap(buffer);
129 PostDecodeAction DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecodeDone(
130 OutputType* buffer) {
131 audio_ts_validator_->RecordOutputDuration(*buffer);
132 return PostDecodeAction::DELIVER;
135 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnConfigChanged(
136 const DecoderConfigType& config) {
137 // Reset validator with the latest config. Also ensures that we do not attempt
138 // to match timestamps across config boundaries.
139 audio_ts_validator_ =
140 std::make_unique<AudioTimestampValidator>(config, media_log_);
143 void DecoderStreamTraits<DemuxerStream::AUDIO>::OnOutputReady(
144 OutputType* buffer) {}
146 // Video decoder stream traits implementation.
149 std::string DecoderStreamTraits<DemuxerStream::VIDEO>::ToString() {
154 bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion(
155 DecoderType* decoder) {
156 return decoder->NeedsBitstreamConversion();
160 scoped_refptr<DecoderStreamTraits<DemuxerStream::VIDEO>::OutputType>
161 DecoderStreamTraits<DemuxerStream::VIDEO>::CreateEOSOutput() {
162 return OutputType::CreateEOSFrame();
165 void DecoderStreamTraits<DemuxerStream::VIDEO>::SetIsPlatformDecoder(
166 bool is_platform_decoder) {
167 stats_.video_pipeline_info.is_platform_decoder = is_platform_decoder;
170 void DecoderStreamTraits<DemuxerStream::VIDEO>::SetIsDecryptingDemuxerStream(
172 stats_.video_pipeline_info.has_decrypting_demuxer_stream = is_dds;
175 void DecoderStreamTraits<DemuxerStream::VIDEO>::SetEncryptionType(
176 EncryptionType encryption_type) {
177 stats_.video_pipeline_info.encryption_type = encryption_type;
180 DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderStreamTraits(
182 // Randomly selected number of samples to keep.
183 : keyframe_distance_average_(16) {
184 weak_this_ = weak_factory_.GetWeakPtr();
187 DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderConfigType
188 DecoderStreamTraits<DemuxerStream::VIDEO>::GetDecoderConfig(
189 DemuxerStream* stream) {
190 return stream->video_decoder_config();
193 void DecoderStreamTraits<DemuxerStream::VIDEO>::ReportStatistics(
194 const StatisticsCB& statistics_cb,
196 stats_.video_bytes_decoded = bytes_decoded;
198 if (keyframe_distance_average_.Count()) {
199 stats_.video_keyframe_distance_average = keyframe_distance_average_.Mean();
201 // Before we have enough keyframes to calculate the average distance, we
202 // will assume the average keyframe distance is infinitely large.
203 stats_.video_keyframe_distance_average = base::TimeDelta::Max();
206 statistics_cb.Run(stats_);
209 void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
210 DecoderType* decoder,
211 const DecoderConfigType& config,
213 CdmContext* cdm_context,
215 const OutputCB& output_cb,
216 const WaitingCB& waiting_cb) {
217 DCHECK(config.IsValidConfig());
218 stats_.video_pipeline_info.decoder_type = VideoDecoderType::kUnknown;
219 transform_ = config.video_transformation();
220 // |decoder| is owned by a DecoderSelector and will stay
221 // alive at least until |init_cb| is finished executing.
223 config, low_delay, cdm_context,
225 &DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized,
226 weak_this_, base::Unretained(decoder), std::move(init_cb)),
227 output_cb, waiting_cb);
230 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized(
231 DecoderType* decoder,
233 DecoderStatus result) {
234 if (result.is_ok()) {
235 stats_.video_pipeline_info.decoder_type = decoder->GetDecoderType();
236 DVLOG(2) << stats_.video_pipeline_info.decoder_type;
238 DVLOG(2) << "Decoder initialization failed.";
240 std::move(cb).Run(result);
243 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
244 DemuxerStream* stream) {
246 last_keyframe_timestamp_ = base::TimeDelta();
247 frame_metadata_.clear();
250 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
251 const DecoderBuffer& buffer) {
252 if (buffer.end_of_stream()) {
253 last_keyframe_timestamp_ = base::TimeDelta();
257 frame_metadata_[buffer.timestamp()] = {
258 buffer.discard_padding().first == kInfiniteDuration, // should_drop
259 buffer.duration(), // duration
260 base::TimeTicks::Now(), // decode_begin_time
263 if (!buffer.is_key_frame())
266 base::TimeDelta current_frame_timestamp = buffer.timestamp();
267 if (last_keyframe_timestamp_.is_zero()) {
268 last_keyframe_timestamp_ = current_frame_timestamp;
272 const base::TimeDelta frame_distance =
273 current_frame_timestamp - last_keyframe_timestamp_;
274 last_keyframe_timestamp_ = current_frame_timestamp;
275 keyframe_distance_average_.AddSample(frame_distance);
278 PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
279 OutputType* buffer) {
280 auto it = frame_metadata_.find(buffer->timestamp());
282 // If the frame isn't in |frame_metadata_| it probably was erased below on a
283 // previous cycle. We could drop these, but today our video algorithm will put
284 // them back into sorted order or drop the frame if a later frame has already
286 if (it == frame_metadata_.end())
287 return PostDecodeAction::DELIVER;
289 // Add a timestamp here to enable buffering delay measurements down the line.
290 buffer->metadata().decode_begin_time = it->second.decode_begin_time;
291 buffer->metadata().decode_end_time = base::TimeTicks::Now();
293 auto action = it->second.should_drop ? PostDecodeAction::DROP
294 : PostDecodeAction::DELIVER;
296 // Provide duration information to help the rendering algorithm on the very
297 // first and very last frames.
298 if (it->second.duration != kNoTimestamp)
299 buffer->metadata().frame_duration = it->second.duration;
301 // We erase from the beginning onward to our target frame since frames should
302 // be returned in presentation order. It's possible to accumulate entries in
303 // this queue if playback begins at a non-keyframe; those frames may never be
304 // returned from the decoder.
305 frame_metadata_.erase(frame_metadata_.begin(), it + 1);
309 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnOutputReady(
310 OutputType* buffer) {
311 buffer->metadata().transformation = transform_;
313 if (!buffer->metadata().decode_begin_time.has_value())
316 // Tag buffer with elapsed time since creation.
317 buffer->metadata().processing_time =
318 base::TimeTicks::Now() - *buffer->metadata().decode_begin_time;
321 void DecoderStreamTraits<DemuxerStream::VIDEO>::SetPreferNonPlatformDecoders(
323 prefer_non_platform_decoders_ = prefer;
326 bool DecoderStreamTraits<DemuxerStream::VIDEO>::GetPreferNonPlatformDecoders()
328 return prefer_non_platform_decoders_;