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 =
200 keyframe_distance_average_.Average();
202 // Before we have enough keyframes to calculate the average distance, we
203 // will assume the average keyframe distance is infinitely large.
204 stats_.video_keyframe_distance_average = base::TimeDelta::Max();
207 statistics_cb.Run(stats_);
210 void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
211 DecoderType* decoder,
212 const DecoderConfigType& config,
214 CdmContext* cdm_context,
216 const OutputCB& output_cb,
217 const WaitingCB& waiting_cb) {
218 DCHECK(config.IsValidConfig());
219 stats_.video_pipeline_info.decoder_type = VideoDecoderType::kUnknown;
220 transform_ = config.video_transformation();
221 // |decoder| is owned by a DecoderSelector and will stay
222 // alive at least until |init_cb| is finished executing.
224 config, low_delay, cdm_context,
226 &DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized,
227 weak_this_, base::Unretained(decoder), std::move(init_cb)),
228 output_cb, waiting_cb);
231 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized(
232 DecoderType* decoder,
234 DecoderStatus result) {
235 if (result.is_ok()) {
236 stats_.video_pipeline_info.decoder_type = decoder->GetDecoderType();
237 DVLOG(2) << stats_.video_pipeline_info.decoder_type;
239 DVLOG(2) << "Decoder initialization failed.";
241 std::move(cb).Run(result);
244 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
245 DemuxerStream* stream) {
247 last_keyframe_timestamp_ = base::TimeDelta();
248 frame_metadata_.clear();
251 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
252 const DecoderBuffer& buffer) {
253 if (buffer.end_of_stream()) {
254 last_keyframe_timestamp_ = base::TimeDelta();
258 frame_metadata_[buffer.timestamp()] = {
259 buffer.discard_padding().first == kInfiniteDuration, // should_drop
260 buffer.duration(), // duration
261 base::TimeTicks::Now(), // decode_begin_time
264 if (!buffer.is_key_frame())
267 base::TimeDelta current_frame_timestamp = buffer.timestamp();
268 if (last_keyframe_timestamp_.is_zero()) {
269 last_keyframe_timestamp_ = current_frame_timestamp;
273 const base::TimeDelta frame_distance =
274 current_frame_timestamp - last_keyframe_timestamp_;
275 last_keyframe_timestamp_ = current_frame_timestamp;
276 keyframe_distance_average_.AddSample(frame_distance);
279 PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
280 OutputType* buffer) {
281 auto it = frame_metadata_.find(buffer->timestamp());
283 // If the frame isn't in |frame_metadata_| it probably was erased below on a
284 // previous cycle. We could drop these, but today our video algorithm will put
285 // them back into sorted order or drop the frame if a later frame has already
287 if (it == frame_metadata_.end())
288 return PostDecodeAction::DELIVER;
290 // Add a timestamp here to enable buffering delay measurements down the line.
291 buffer->metadata().decode_begin_time = it->second.decode_begin_time;
292 buffer->metadata().decode_end_time = base::TimeTicks::Now();
294 auto action = it->second.should_drop ? PostDecodeAction::DROP
295 : PostDecodeAction::DELIVER;
297 // Provide duration information to help the rendering algorithm on the very
298 // first and very last frames.
299 if (it->second.duration != kNoTimestamp)
300 buffer->metadata().frame_duration = it->second.duration;
302 // We erase from the beginning onward to our target frame since frames should
303 // be returned in presentation order. It's possible to accumulate entries in
304 // this queue if playback begins at a non-keyframe; those frames may never be
305 // returned from the decoder.
306 frame_metadata_.erase(frame_metadata_.begin(), it + 1);
310 void DecoderStreamTraits<DemuxerStream::VIDEO>::OnOutputReady(
311 OutputType* buffer) {
312 buffer->metadata().transformation = transform_;
314 if (!buffer->metadata().decode_begin_time.has_value())
317 // Tag buffer with elapsed time since creation.
318 buffer->metadata().processing_time =
319 base::TimeTicks::Now() - *buffer->metadata().decode_begin_time;
322 void DecoderStreamTraits<DemuxerStream::VIDEO>::SetPreferNonPlatformDecoders(
324 prefer_non_platform_decoders_ = prefer;
327 bool DecoderStreamTraits<DemuxerStream::VIDEO>::GetPreferNonPlatformDecoders()
329 return prefer_non_platform_decoders_;