summaryrefslogtreecommitdiff
path: root/chromium/media/filters
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/media/filters
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/media/filters')
-rw-r--r--chromium/media/filters/BUILD.gn2
-rw-r--r--chromium/media/filters/android/media_codec_audio_decoder.cc4
-rw-r--r--chromium/media/filters/android/media_codec_audio_decoder.h1
-rw-r--r--chromium/media/filters/audio_decoder_stream_unittest.cc3
-rw-r--r--chromium/media/filters/audio_decoder_unittest.cc10
-rw-r--r--chromium/media/filters/audio_file_reader.cc22
-rw-r--r--chromium/media/filters/audio_video_metadata_extractor_unittest.cc23
-rw-r--r--chromium/media/filters/chunk_demuxer.cc130
-rw-r--r--chromium/media/filters/chunk_demuxer.h39
-rw-r--r--chromium/media/filters/chunk_demuxer_unittest.cc4
-rw-r--r--chromium/media/filters/dav1d_video_decoder.cc16
-rw-r--r--chromium/media/filters/dav1d_video_decoder.h4
-rw-r--r--chromium/media/filters/dav1d_video_decoder_unittest.cc2
-rw-r--r--chromium/media/filters/decoder_selector.cc30
-rw-r--r--chromium/media/filters/decoder_selector_unittest.cc67
-rw-r--r--chromium/media/filters/decoder_stream.cc54
-rw-r--r--chromium/media/filters/decoder_stream.h23
-rw-r--r--chromium/media/filters/decoder_stream_traits.cc64
-rw-r--r--chromium/media/filters/decoder_stream_traits.h10
-rw-r--r--chromium/media/filters/decrypting_audio_decoder.cc4
-rw-r--r--chromium/media/filters/decrypting_audio_decoder.h1
-rw-r--r--chromium/media/filters/decrypting_audio_decoder_unittest.cc26
-rw-r--r--chromium/media/filters/decrypting_video_decoder.cc6
-rw-r--r--chromium/media/filters/decrypting_video_decoder.h1
-rw-r--r--chromium/media/filters/decrypting_video_decoder_unittest.cc24
-rw-r--r--chromium/media/filters/demuxer_perftest.cc10
-rw-r--r--chromium/media/filters/fake_video_decoder.cc4
-rw-r--r--chromium/media/filters/fake_video_decoder.h1
-rw-r--r--chromium/media/filters/fake_video_decoder_unittest.cc2
-rw-r--r--chromium/media/filters/ffmpeg_audio_decoder.cc4
-rw-r--r--chromium/media/filters/ffmpeg_audio_decoder.h1
-rw-r--r--chromium/media/filters/ffmpeg_demuxer.cc13
-rw-r--r--chromium/media/filters/ffmpeg_demuxer_unittest.cc8
-rw-r--r--chromium/media/filters/ffmpeg_glue_unittest.cc4
-rw-r--r--chromium/media/filters/ffmpeg_video_decoder.cc37
-rw-r--r--chromium/media/filters/ffmpeg_video_decoder.h3
-rw-r--r--chromium/media/filters/ffmpeg_video_decoder_unittest.cc2
-rw-r--r--chromium/media/filters/fuchsia/fuchsia_video_decoder.cc21
-rw-r--r--chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc10
-rw-r--r--chromium/media/filters/gav1_video_decoder.cc16
-rw-r--r--chromium/media/filters/gav1_video_decoder.h4
-rw-r--r--chromium/media/filters/gav1_video_decoder_unittest.cc2
-rw-r--r--chromium/media/filters/memory_data_source.h5
-rw-r--r--chromium/media/filters/offloading_video_decoder.cc5
-rw-r--r--chromium/media/filters/offloading_video_decoder.h1
-rw-r--r--chromium/media/filters/offloading_video_decoder_unittest.cc5
-rw-r--r--chromium/media/filters/pipeline_controller.cc4
-rw-r--r--chromium/media/filters/pipeline_controller.h1
-rw-r--r--chromium/media/filters/pipeline_controller_unittest.cc4
-rw-r--r--chromium/media/filters/source_buffer_state.cc55
-rw-r--r--chromium/media/filters/source_buffer_state.h5
-rw-r--r--chromium/media/filters/stream_parser_factory.cc52
-rw-r--r--chromium/media/filters/stream_parser_factory.h20
-rw-r--r--chromium/media/filters/video_decoder_stream_unittest.cc75
-rw-r--r--chromium/media/filters/video_renderer_algorithm.cc8
-rw-r--r--chromium/media/filters/video_renderer_algorithm_unittest.cc12
-rw-r--r--chromium/media/filters/vp9_parser.h2
-rw-r--r--chromium/media/filters/vp9_uncompressed_header_parser.cc9
-rw-r--r--chromium/media/filters/vp9_uncompressed_header_parser.h8
-rw-r--r--chromium/media/filters/vp9_uncompressed_header_parser_unittest.cc65
-rw-r--r--chromium/media/filters/vpx_video_decoder.cc27
-rw-r--r--chromium/media/filters/vpx_video_decoder.h4
-rw-r--r--chromium/media/filters/vpx_video_decoder_fuzzertest.cc8
-rw-r--r--chromium/media/filters/vpx_video_decoder_unittest.cc2
64 files changed, 883 insertions, 206 deletions
diff --git a/chromium/media/filters/BUILD.gn b/chromium/media/filters/BUILD.gn
index 573ef0ee042..3cc37a4379f 100644
--- a/chromium/media/filters/BUILD.gn
+++ b/chromium/media/filters/BUILD.gn
@@ -4,7 +4,6 @@
import("//media/gpu/args.gni")
import("//media/media_options.gni")
-import("//third_party/libaom/options.gni")
source_set("filters") {
# Do not expand the visibility here without double-checking with OWNERS, this
@@ -300,6 +299,7 @@ source_set("unit_tests") {
"video_renderer_algorithm_unittest.cc",
"vp9_parser_unittest.cc",
"vp9_raw_bits_reader_unittest.cc",
+ "vp9_uncompressed_header_parser_unittest.cc",
]
deps = [
diff --git a/chromium/media/filters/android/media_codec_audio_decoder.cc b/chromium/media/filters/android/media_codec_audio_decoder.cc
index 587b78c1a30..5119af0a8bd 100644
--- a/chromium/media/filters/android/media_codec_audio_decoder.cc
+++ b/chromium/media/filters/android/media_codec_audio_decoder.cc
@@ -52,6 +52,10 @@ std::string MediaCodecAudioDecoder::GetDisplayName() const {
return "MediaCodecAudioDecoder";
}
+AudioDecoderType MediaCodecAudioDecoder::GetDecoderType() const {
+ return AudioDecoderType::kMediaCodec;
+}
+
void MediaCodecAudioDecoder::Initialize(const AudioDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb,
diff --git a/chromium/media/filters/android/media_codec_audio_decoder.h b/chromium/media/filters/android/media_codec_audio_decoder.h
index 54414590150..f5d7238913c 100644
--- a/chromium/media/filters/android/media_codec_audio_decoder.h
+++ b/chromium/media/filters/android/media_codec_audio_decoder.h
@@ -86,6 +86,7 @@ class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder,
// AudioDecoder implementation.
std::string GetDisplayName() const override;
+ AudioDecoderType GetDecoderType() const override;
void Initialize(const AudioDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb,
diff --git a/chromium/media/filters/audio_decoder_stream_unittest.cc b/chromium/media/filters/audio_decoder_stream_unittest.cc
index 483b0fa0b6d..9e6475c2042 100644
--- a/chromium/media/filters/audio_decoder_stream_unittest.cc
+++ b/chromium/media/filters/audio_decoder_stream_unittest.cc
@@ -110,8 +110,7 @@ class AudioDecoderStreamTest : public testing::Test {
}
void OnAudioBufferReadDone(base::OnceClosure closure,
- AudioDecoderStream::ReadStatus status,
- scoped_refptr<AudioBuffer> audio_buffer) {
+ AudioDecoderStream::ReadResult result) {
std::move(closure).Run();
}
diff --git a/chromium/media/filters/audio_decoder_unittest.cc b/chromium/media/filters/audio_decoder_unittest.cc
index c02f516e192..d54d50b2c85 100644
--- a/chromium/media/filters/audio_decoder_unittest.cc
+++ b/chromium/media/filters/audio_decoder_unittest.cc
@@ -62,7 +62,7 @@ namespace {
// The number of packets to read and then decode from each file.
const size_t kDecodeRuns = 3;
-enum AudioDecoderType {
+enum TestAudioDecoderType {
FFMPEG,
#if defined(OS_ANDROID)
MEDIA_CODEC,
@@ -123,7 +123,7 @@ void SetDiscardPadding(AVPacket* packet,
} // namespace
class AudioDecoderTest
- : public TestWithParam<std::tuple<AudioDecoderType, TestParams>> {
+ : public TestWithParam<std::tuple<TestAudioDecoderType, TestParams>> {
public:
AudioDecoderTest()
: decoder_type_(std::get<0>(GetParam())),
@@ -301,12 +301,12 @@ class AudioDecoderTest
decoded_audio_.push_back(std::move(buffer));
}
- void DecodeFinished(const base::Closure& quit_closure, Status status) {
+ void DecodeFinished(base::OnceClosure quit_closure, Status status) {
EXPECT_TRUE(pending_decode_);
EXPECT_FALSE(pending_reset_);
pending_decode_ = false;
last_decode_status_ = std::move(status);
- quit_closure.Run();
+ std::move(quit_closure).Run();
}
void ResetFinished() {
@@ -392,7 +392,7 @@ class AudioDecoderTest
const Status& last_decode_status() const { return last_decode_status_; }
private:
- const AudioDecoderType decoder_type_;
+ const TestAudioDecoderType decoder_type_;
// Current TestParams used to initialize the test and decoder. The initial
// valie is std::get<1>(GetParam()). Could be overridden by set_param() so
diff --git a/chromium/media/filters/audio_file_reader.cc b/chromium/media/filters/audio_file_reader.cc
index cb81d920def..df95bac9730 100644
--- a/chromium/media/filters/audio_file_reader.cc
+++ b/chromium/media/filters/audio_file_reader.cc
@@ -276,9 +276,25 @@ bool AudioFileReader::OnNewFrame(
sizeof(float) * frames_read);
}
} else {
- audio_bus->FromInterleaved(
- frame->data[0], frames_read,
- av_get_bytes_per_sample(codec_context_->sample_fmt));
+ int bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt);
+ switch (bytes_per_sample) {
+ case 1:
+ audio_bus->FromInterleaved<UnsignedInt8SampleTypeTraits>(
+ reinterpret_cast<const uint8_t*>(frame->data[0]), frames_read);
+ break;
+ case 2:
+ audio_bus->FromInterleaved<SignedInt16SampleTypeTraits>(
+ reinterpret_cast<const int16_t*>(frame->data[0]), frames_read);
+ break;
+ case 4:
+ audio_bus->FromInterleaved<SignedInt32SampleTypeTraits>(
+ reinterpret_cast<const int32_t*>(frame->data[0]), frames_read);
+ break;
+ default:
+ NOTREACHED() << "Unsupported bytes per sample encountered: "
+ << bytes_per_sample;
+ audio_bus->ZeroFrames(frames_read);
+ }
}
(*total_frames) += frames_read;
diff --git a/chromium/media/filters/audio_video_metadata_extractor_unittest.cc b/chromium/media/filters/audio_video_metadata_extractor_unittest.cc
index df1cb131eb3..b26dd2c3a4c 100644
--- a/chromium/media/filters/audio_video_metadata_extractor_unittest.cc
+++ b/chromium/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -55,6 +55,19 @@ const std::string GetTagValue(
return tag_data->second;
}
+const std::string TagsToString(
+ const media::AudioVideoMetadataExtractor::TagDictionary& tags) {
+ std::string result;
+ for (auto& kv : tags) {
+ if (!result.empty())
+ result += " | ";
+ result += kv.first;
+ result += ": ";
+ result += kv.second;
+ }
+ return result;
+}
+
TEST(AudioVideoMetadataExtractorTest, InvalidFile) {
GetExtractor("ten_byte_file", true, false, 0, -1, -1);
}
@@ -172,16 +185,19 @@ TEST(AudioVideoMetadataExtractorTest, AndroidRotatedMP4Video) {
GetTagValue(extractor->stream_infos()[0].tags, "minor_version"));
EXPECT_EQ("h264", extractor->stream_infos()[1].type);
- EXPECT_EQ(5u, extractor->stream_infos()[1].tags.size());
+ EXPECT_EQ(6u, extractor->stream_infos()[1].tags.size())
+ << "Tags: " << TagsToString(extractor->stream_infos()[1].tags);
EXPECT_EQ("2014-02-11T00:39:25.000000Z",
GetTagValue(extractor->stream_infos()[1].tags, "creation_time"));
EXPECT_EQ("VideoHandle",
GetTagValue(extractor->stream_infos()[1].tags, "handler_name"));
+ EXPECT_EQ("MOTO", GetTagValue(extractor->stream_infos()[1].tags, "encoder"));
EXPECT_EQ("eng", GetTagValue(extractor->stream_infos()[1].tags, "language"));
EXPECT_EQ("90", GetTagValue(extractor->stream_infos()[1].tags, "rotate"));
EXPECT_EQ("aac", extractor->stream_infos()[2].type);
- EXPECT_EQ(3u, extractor->stream_infos()[2].tags.size());
+ EXPECT_EQ(4u, extractor->stream_infos()[2].tags.size())
+ << "Tags: " << TagsToString(extractor->stream_infos()[2].tags);
EXPECT_EQ("2014-02-11T00:39:25.000000Z",
GetTagValue(extractor->stream_infos()[2].tags, "creation_time"));
EXPECT_EQ("SoundHandle",
@@ -258,7 +274,8 @@ TEST(AudioVideoMetadataExtractorTest, AudioFLACInMp4) {
GetTagValue(extractor->stream_infos()[0].tags, "encoder"));
EXPECT_EQ("flac", extractor->stream_infos()[1].type);
- EXPECT_EQ(2u, extractor->stream_infos()[1].tags.size());
+ EXPECT_EQ(3u, extractor->stream_infos()[1].tags.size())
+ << "Tags: " << TagsToString(extractor->stream_infos()[1].tags);
EXPECT_EQ("SoundHandler",
GetTagValue(extractor->stream_infos()[1].tags, "handler_name"));
EXPECT_EQ("und", GetTagValue(extractor->stream_infos()[1].tags, "language"));
diff --git a/chromium/media/filters/chunk_demuxer.cc b/chromium/media/filters/chunk_demuxer.cc
index 9f0f2cc5999..2165cd2f121 100644
--- a/chromium/media/filters/chunk_demuxer.cc
+++ b/chromium/media/filters/chunk_demuxer.cc
@@ -624,6 +624,58 @@ void ChunkDemuxer::CancelPendingSeek(TimeDelta seek_time) {
RunSeekCB_Locked(PIPELINE_OK);
}
+ChunkDemuxer::Status ChunkDemuxer::AddId(
+ const std::string& id,
+ std::unique_ptr<AudioDecoderConfig> audio_config) {
+ DCHECK(audio_config);
+ DVLOG(1) << __func__ << " id="
+ << " audio_config=" << audio_config->AsHumanReadableString();
+ base::AutoLock auto_lock(lock_);
+
+ // Any valid audio config provided by WC is bufferable here, though decode
+ // error may occur later.
+ if (!audio_config->IsValidConfig())
+ return ChunkDemuxer::kNotSupported;
+
+ if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
+ return kReachedIdLimit;
+
+ DCHECK(init_cb_);
+
+ std::string expected_codec = GetCodecName(audio_config->codec());
+ std::unique_ptr<media::StreamParser> stream_parser(
+ media::StreamParserFactory::Create(std::move(audio_config)));
+ DCHECK(stream_parser);
+
+ return AddIdInternal(id, std::move(stream_parser), expected_codec);
+}
+
+ChunkDemuxer::Status ChunkDemuxer::AddId(
+ const std::string& id,
+ std::unique_ptr<VideoDecoderConfig> video_config) {
+ DCHECK(video_config);
+ DVLOG(1) << __func__ << " id="
+ << " video_config=" << video_config->AsHumanReadableString();
+ base::AutoLock auto_lock(lock_);
+
+ // Any valid video config provided by WC is bufferable here, though decode
+ // error may occur later.
+ if (!video_config->IsValidConfig())
+ return ChunkDemuxer::kNotSupported;
+
+ if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
+ return kReachedIdLimit;
+
+ DCHECK(init_cb_);
+
+ std::string expected_codec = GetCodecName(video_config->codec());
+ std::unique_ptr<media::StreamParser> stream_parser(
+ media::StreamParserFactory::Create(std::move(video_config)));
+ DCHECK(stream_parser);
+
+ return AddIdInternal(id, std::move(stream_parser), expected_codec);
+}
+
ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
const std::string& content_type,
const std::string& codecs) {
@@ -646,6 +698,18 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
return ChunkDemuxer::kNotSupported;
}
+ return AddIdInternal(id, std::move(stream_parser),
+ ExpectedCodecs(content_type, codecs));
+}
+
+ChunkDemuxer::Status ChunkDemuxer::AddIdInternal(
+ const std::string& id,
+ std::unique_ptr<media::StreamParser> stream_parser,
+ std::string expected_codecs) {
+ DVLOG(2) << __func__ << " id=" << id
+ << " expected_codecs=" << expected_codecs;
+ lock_.AssertAcquired();
+
std::unique_ptr<FrameProcessor> frame_processor =
std::make_unique<FrameProcessor>(
base::BindRepeating(&ChunkDemuxer::IncreaseDurationIfNecessary,
@@ -670,8 +734,8 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
source_state->Init(base::BindOnce(&ChunkDemuxer::OnSourceInitDone,
base::Unretained(this), id),
- ExpectedCodecs(content_type, codecs),
- encrypted_media_init_data_cb_, base::NullCallback());
+ expected_codecs, encrypted_media_init_data_cb_,
+ base::NullCallback());
// TODO(wolenetz): Change to DCHECKs once less verification in release build
// is needed. See https://crbug.com/786975.
@@ -900,6 +964,66 @@ bool ChunkDemuxer::AppendData(const std::string& id,
return true;
}
+bool ChunkDemuxer::AppendChunks(
+ const std::string& id,
+ std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
+ base::TimeDelta append_window_start,
+ base::TimeDelta append_window_end,
+ base::TimeDelta* timestamp_offset) {
+ DCHECK(buffer_queue);
+ DVLOG(1) << __func__ << ": " << id
+ << ", buffer_queue size()=" << buffer_queue->size();
+
+ DCHECK(!id.empty());
+ DCHECK(timestamp_offset);
+
+ Ranges<TimeDelta> ranges;
+
+ {
+ base::AutoLock auto_lock(lock_);
+ DCHECK_NE(state_, ENDED);
+
+ // Capture if any of the SourceBuffers are waiting for data before we start
+ // buffering new chunks.
+ bool old_waiting_for_data = IsSeekWaitingForData_Locked();
+
+ if (buffer_queue->size() == 0u)
+ return true;
+
+ switch (state_) {
+ case INITIALIZING:
+ case INITIALIZED:
+ DCHECK(IsValidId(id));
+ if (!source_state_map_[id]->AppendChunks(
+ std::move(buffer_queue), append_window_start, append_window_end,
+ timestamp_offset)) {
+ ReportError_Locked(CHUNK_DEMUXER_ERROR_APPEND_FAILED);
+ return false;
+ }
+ break;
+
+ case PARSE_ERROR:
+ case WAITING_FOR_INIT:
+ case ENDED:
+ case SHUTDOWN:
+ DVLOG(1) << "AppendChunks(): called in unexpected state " << state_;
+ return false;
+ }
+
+ // Check to see if data was appended at the pending seek point. This
+ // indicates we have parsed enough data to complete the seek. Work is still
+ // in progress at this point, but it's okay since |seek_cb_| will post.
+ if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
+ RunSeekCB_Locked(PIPELINE_OK);
+
+ ranges = GetBufferedRanges_Locked();
+ }
+
+ host_->OnBufferedTimeRangesChanged(ranges);
+ progress_cb_.Run();
+ return true;
+}
+
void ChunkDemuxer::ResetParserState(const std::string& id,
TimeDelta append_window_start,
TimeDelta append_window_end,
@@ -1294,7 +1418,7 @@ ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
DemuxerStream::Type type) {
// New ChunkDemuxerStreams can be created only during initialization segment
// processing, which happens when a new chunk of data is appended and the
- // lock_ must be held by ChunkDemuxer::AppendData.
+ // lock_ must be held by ChunkDemuxer::AppendData/Chunks.
lock_.AssertAcquired();
MediaTrack::Id media_track_id = GenerateMediaTrackId();
diff --git a/chromium/media/filters/chunk_demuxer.h b/chromium/media/filters/chunk_demuxer.h
index f86d931e9a0..68a2488a13a 100644
--- a/chromium/media/filters/chunk_demuxer.h
+++ b/chromium/media/filters/chunk_demuxer.h
@@ -33,6 +33,9 @@ class MEDIA_EXPORT SourceBufferStream;
namespace media {
+class AudioDecoderConfig;
+class VideoDecoderConfig;
+
class MEDIA_EXPORT ChunkDemuxerStream : public DemuxerStream {
public:
using BufferQueue = base::circular_deque<scoped_refptr<StreamParserBuffer>>;
@@ -199,7 +202,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
};
// |open_cb| Run when Initialize() is called to signal that the demuxer
- // is ready to receive media data via AppendData().
+ // is ready to receive media data via AppendData/Chunks().
// |progress_cb| Run each time data is appended.
// |encrypted_media_init_data_cb| Run when the demuxer determines that an
// encryption key is needed to decrypt the content.
@@ -233,17 +236,25 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
void StartWaitingForSeek(base::TimeDelta seek_time) override;
void CancelPendingSeek(base::TimeDelta seek_time) override;
- // Registers a new |id| to use for AppendData() calls. |content_type|
+ // Registers a new |id| to use for AppendData/Chunks() calls. |content_type|
// indicates the MIME type's ContentType and |codecs| indicates the MIME
// type's "codecs" parameter string (if any) for the data that we intend to
// append for this ID. kOk is returned if the demuxer has enough resources to
// support another ID and supports the format indicated by |content_type| and
- // |codecs|. kReachedIdLimit is returned if the demuxer cannot handle another
- // ID right now. kNotSupported is returned if |content_type| and |codecs| is
+ // |codecs|. kReachedIdLimit is returned if the demuxer cannot handle another
+ // ID right now. kNotSupported is returned if |content_type| and |codecs| is
// not a supported format.
+ // The |audio_config| and |video_config| overloads behave similarly, except
+ // the caller must provide valid, supported decoder configs; those overloads'
+ // usage indicates that we intend to append WebCodecs encoded audio or video
+ // chunks for this ID.
Status AddId(const std::string& id,
const std::string& content_type,
const std::string& codecs);
+ Status AddId(const std::string& id,
+ std::unique_ptr<AudioDecoderConfig> audio_config);
+ Status AddId(const std::string& id,
+ std::unique_ptr<VideoDecoderConfig> video_config);
// Notifies a caller via |tracks_updated_cb| that the set of media tracks
// for a given |id| has changed.
@@ -286,6 +297,16 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
base::TimeDelta append_window_end,
base::TimeDelta* timestamp_offset);
+ // Appends webcodecs encoded chunks (already converted by caller into a
+ // BufferQueue of StreamParserBuffers) to the source buffer associated with
+ // |id|, with same semantic for other parameters and return value as
+ // AppendData().
+ bool AppendChunks(const std::string& id,
+ std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
+ base::TimeDelta append_window_start,
+ base::TimeDelta append_window_end,
+ base::TimeDelta* timestamp_offset);
+
// Aborts parsing the current segment and reset the parser to a state where
// it can accept a new segment.
// Some pending frames can be emitted during that process. These frames are
@@ -393,6 +414,14 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
SHUTDOWN,
};
+ // Helper for AddId's creation of FrameProcessor, and
+ // SourceBufferState creation, initialization and tracking in
+ // source_state_map_.
+ ChunkDemuxer::Status AddIdInternal(
+ const std::string& id,
+ std::unique_ptr<media::StreamParser> stream_parser,
+ std::string expected_codecs);
+
// Helper for vide and audio track changing.
void FindAndEnableProperTracks(const std::vector<MediaTrack::Id>& track_ids,
base::TimeDelta curr_time,
@@ -499,7 +528,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
base::TimeDelta duration_;
// The duration passed to the last SetDuration(). If
- // SetDuration() is never called or an AppendData() call or
+ // SetDuration() is never called or an AppendData/Chunks() call or
// a EndOfStream() call changes |duration_|, then this
// variable is set to < 0 to indicate that the |duration_| represents
// the actual duration instead of a user specified value.
diff --git a/chromium/media/filters/chunk_demuxer_unittest.cc b/chromium/media/filters/chunk_demuxer_unittest.cc
index 2ed13c82723..a3de1346858 100644
--- a/chromium/media/filters/chunk_demuxer_unittest.cc
+++ b/chromium/media/filters/chunk_demuxer_unittest.cc
@@ -4388,10 +4388,10 @@ TEST_F(ChunkDemuxerTest,
}
namespace {
-void QuitLoop(base::Closure quit_closure,
+void QuitLoop(base::OnceClosure quit_closure,
DemuxerStream::Type type,
const std::vector<DemuxerStream*>& streams) {
- quit_closure.Run();
+ std::move(quit_closure).Run();
}
void DisableAndEnableDemuxerTracks(
diff --git a/chromium/media/filters/dav1d_video_decoder.cc b/chromium/media/filters/dav1d_video_decoder.cc
index bb31801e439..7e5eaf5b245 100644
--- a/chromium/media/filters/dav1d_video_decoder.cc
+++ b/chromium/media/filters/dav1d_video_decoder.cc
@@ -129,6 +129,16 @@ struct ScopedDav1dPictureFree {
}
};
+// static
+SupportedVideoDecoderConfigs Dav1dVideoDecoder::SupportedConfigs() {
+ return {{/*profile_min=*/AV1PROFILE_PROFILE_MAIN,
+ /*profile_max=*/AV1PROFILE_PROFILE_HIGH,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false}};
+}
+
Dav1dVideoDecoder::Dav1dVideoDecoder(MediaLog* media_log,
OffloadState offload_state)
: media_log_(media_log),
@@ -145,6 +155,10 @@ std::string Dav1dVideoDecoder::GetDisplayName() const {
return "Dav1dVideoDecoder";
}
+VideoDecoderType Dav1dVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kDav1d;
+}
+
void Dav1dVideoDecoder::Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* /* cdm_context */,
@@ -368,7 +382,7 @@ bool Dav1dVideoDecoder::DecodeBuffer(scoped_refptr<DecoderBuffer> buffer) {
color_space = config_.color_space_info();
frame->set_color_space(color_space.ToGfxColorSpace());
- frame->metadata()->power_efficient = false;
+ frame->metadata().power_efficient = false;
frame->set_hdr_metadata(config_.hdr_metadata());
// When we use bind mode, our image data is dependent on the Dav1dPicture,
diff --git a/chromium/media/filters/dav1d_video_decoder.h b/chromium/media/filters/dav1d_video_decoder.h
index 22c4e1fd381..689628ae07e 100644
--- a/chromium/media/filters/dav1d_video_decoder.h
+++ b/chromium/media/filters/dav1d_video_decoder.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/sequence_checker.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
@@ -24,11 +25,14 @@ class MediaLog;
class MEDIA_EXPORT Dav1dVideoDecoder : public OffloadableVideoDecoder {
public:
+ static SupportedVideoDecoderConfigs SupportedConfigs();
+
Dav1dVideoDecoder(MediaLog* media_log,
OffloadState offload_state = OffloadState::kNormal);
~Dav1dVideoDecoder() override;
// VideoDecoder implementation.
+ VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
diff --git a/chromium/media/filters/dav1d_video_decoder_unittest.cc b/chromium/media/filters/dav1d_video_decoder_unittest.cc
index 19572a06873..0711b2f9e7e 100644
--- a/chromium/media/filters/dav1d_video_decoder_unittest.cc
+++ b/chromium/media/filters/dav1d_video_decoder_unittest.cc
@@ -169,7 +169,7 @@ class Dav1dVideoDecoderTest : public testing::Test {
}
void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
output_frames_.push_back(std::move(frame));
}
diff --git a/chromium/media/filters/decoder_selector.cc b/chromium/media/filters/decoder_selector.cc
index adba332ab89..ac99eae91ca 100644
--- a/chromium/media/filters/decoder_selector.cc
+++ b/chromium/media/filters/decoder_selector.cc
@@ -33,9 +33,25 @@ namespace {
const char kSelectDecoderTrace[] = "DecoderSelector::SelectDecoder";
+bool SkipDecoderForRTC(const AudioDecoderConfig& /*config*/,
+ const AudioDecoder& /*decoder*/) {
+ return false;
+}
+
+bool SkipDecoderForRTC(const VideoDecoderConfig& config,
+ const VideoDecoder& decoder) {
+ // For now, we assume that RTC decoders are able to decode non-RTC streams,
+ // presumably by configuring themselves based on the config's rtc bit. Since
+ // no decoders take any action at all based on it, this is as good as any.
+ return config.is_rtc() && !decoder.IsOptimizedForRTC();
+}
+
template <typename ConfigT, typename DecoderT>
-DecoderPriority NormalDecoderPriority(const ConfigT& /*config*/,
- const DecoderT& /*decoder*/) {
+DecoderPriority NormalDecoderPriority(const ConfigT& config,
+ const DecoderT& decoder) {
+ if (SkipDecoderForRTC(config, decoder))
+ return DecoderPriority::kSkipped;
+
return DecoderPriority::kNormal;
}
@@ -43,12 +59,15 @@ DecoderPriority ResolutionBasedDecoderPriority(const VideoDecoderConfig& config,
const VideoDecoder& decoder) {
#if defined(OS_ANDROID)
constexpr auto kSoftwareDecoderHeightCutoff = 360;
-#elif BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
constexpr auto kSoftwareDecoderHeightCutoff = 360;
#else
constexpr auto kSoftwareDecoderHeightCutoff = 720;
#endif
+ if (SkipDecoderForRTC(config, decoder))
+ return DecoderPriority::kSkipped;
+
// We only do a height check to err on the side of prioritizing platform
// decoders.
const auto at_or_above_software_cutoff =
@@ -62,8 +81,11 @@ DecoderPriority ResolutionBasedDecoderPriority(const VideoDecoderConfig& config,
}
template <typename ConfigT, typename DecoderT>
-DecoderPriority SkipNonPlatformDecoders(const ConfigT& /*config*/,
+DecoderPriority SkipNonPlatformDecoders(const ConfigT& config,
const DecoderT& decoder) {
+ if (SkipDecoderForRTC(config, decoder))
+ return DecoderPriority::kSkipped;
+
return decoder.IsPlatformDecoder() ? DecoderPriority::kNormal
: DecoderPriority::kSkipped;
}
diff --git a/chromium/media/filters/decoder_selector_unittest.cc b/chromium/media/filters/decoder_selector_unittest.cc
index db84317a22c..e32c8d0e32c 100644
--- a/chromium/media/filters/decoder_selector_unittest.cc
+++ b/chromium/media/filters/decoder_selector_unittest.cc
@@ -164,6 +164,8 @@ class AudioDecoderSelectorTestParam {
static void ExpectNotInitialize(MockDecoder* decoder) {
EXPECT_CALL(*decoder, Initialize_(_, _, _, _, _)).Times(0);
}
+
+ static void SetRTCDecoderness(MockDecoder* decoder, bool is_rtc_decoder) {}
};
// Allocate storage for the member variables.
@@ -246,6 +248,11 @@ class VideoDecoderSelectorTestParam {
static void ExpectNotInitialize(MockDecoder* decoder) {
EXPECT_CALL(*decoder, Initialize_(_, _, _, _, _, _)).Times(0);
}
+
+ static void SetRTCDecoderness(MockDecoder* decoder, bool is_optimized) {
+ EXPECT_CALL(*decoder, IsOptimizedForRTC())
+ .WillRepeatedly(Return(is_optimized));
+ }
};
// Allocate storate for the member variables.
@@ -289,6 +296,7 @@ class DecoderSelectorTest : public ::testing::Test {
bool supports_decryption;
bool is_platform_decoder;
bool expect_not_initialized;
+ bool is_rtc_decoder = false;
};
DecoderSelectorTest()
@@ -330,6 +338,14 @@ class DecoderSelectorTest : public ::testing::Test {
AddMockDecoder(std::move(args));
}
+ void AddMockRTCPlatformDecoder(const std::string& decoder_name,
+ DecoderCapability capability) {
+ auto args = MockDecoderArgs::Create(std::move(decoder_name), capability);
+ args.is_rtc_decoder = true;
+ args.is_platform_decoder = true;
+ AddMockDecoder(std::move(args));
+ }
+
void AddMockDecoder(MockDecoderArgs args) {
// Actual decoders are created in CreateDecoders(), which may be called
// multiple times by the DecoderSelector.
@@ -357,6 +373,7 @@ class DecoderSelectorTest : public ::testing::Test {
} else {
TypeParam::ExpectInitialize(decoder.get(), args.capability);
}
+ TypeParam::SetRTCDecoderness(decoder.get(), args.is_rtc_decoder);
decoders.push_back(std::move(decoder));
}
@@ -1049,4 +1066,54 @@ TEST_F(VideoDecoderSelectorTest, EncryptedStream_PrioritizePlatformDecoders) {
this->SelectDecoder();
}
+// Tests that the normal decoder selector rule skips non-RTC decoders for RTC.
+TEST_F(VideoDecoderSelectorTest, RTC_NormalPriority) {
+ base::test::ScopedFeatureList features;
+
+ this->AddMockDecoder(kDecoder1, kAlwaysSucceed);
+ this->AddMockRTCPlatformDecoder(kDecoder2, kAlwaysSucceed);
+
+ auto config = TestVideoConfig::Custom(gfx::Size(4096, 4096));
+ config.set_is_rtc(true);
+ this->demuxer_stream_.set_video_decoder_config(config);
+ this->CreateDecoderSelector();
+
+ EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
+ this->SelectDecoder();
+}
+
+// Tests that the resolution-based rule skips non-RTC decoders for RTC.
+TEST_F(VideoDecoderSelectorTest, RTC_DecoderBasedPriority) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(kResolutionBasedDecoderPriority);
+
+ this->AddMockDecoder(kDecoder1, kAlwaysSucceed);
+ this->AddMockRTCPlatformDecoder(kDecoder2, kAlwaysSucceed);
+
+ auto config = TestVideoConfig::Custom(gfx::Size(4096, 4096));
+ config.set_is_rtc(true);
+ this->demuxer_stream_.set_video_decoder_config(config);
+ this->CreateDecoderSelector();
+
+ EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
+ this->SelectDecoder();
+}
+
+// Tests that the hardware-based rule skips non-RTC decoders for RTC.
+TEST_F(VideoDecoderSelectorTest, RTC_ForceHardwareDecoders) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(kForceHardwareVideoDecoders);
+
+ this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed);
+ this->AddMockRTCPlatformDecoder(kDecoder2, kAlwaysSucceed);
+
+ auto config = TestVideoConfig::Custom(gfx::Size(4096, 4096));
+ config.set_is_rtc(true);
+ this->demuxer_stream_.set_video_decoder_config(config);
+ this->CreateDecoderSelector();
+
+ EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
+ this->SelectDecoder();
+}
+
} // namespace media
diff --git a/chromium/media/filters/decoder_stream.cc b/chromium/media/filters/decoder_stream.cc
index c4b4c806d6c..bf80bb13684 100644
--- a/chromium/media/filters/decoder_stream.cc
+++ b/chromium/media/filters/decoder_stream.cc
@@ -78,17 +78,14 @@ const char* GetPrepareTraceString<DemuxerStream::AUDIO>() {
return "AudioDecoderStream::PrepareOutput";
}
-template <DemuxerStream::Type StreamType>
-const char* GetStatusString(
- typename DecoderStream<StreamType>::ReadStatus status) {
- switch (status) {
- case DecoderStream<StreamType>::OK:
+const char* GetStatusString(const Status& status) {
+ // TODO(crbug.com/1129662): Replace this with generic Status-to-string.
+ switch (status.code()) {
+ case StatusCode::kOk:
return "okay";
- case DecoderStream<StreamType>::ABORTED:
+ case StatusCode::kAborted:
return "aborted";
- case DecoderStream<StreamType>::DEMUXER_READ_ABORTED:
- return "demuxer_read_aborted";
- case DecoderStream<StreamType>::DECODE_ERROR:
+ default:
return "decode_error";
}
@@ -130,7 +127,7 @@ DecoderStream<StreamType>::~DecoderStream() {
}
if (read_cb_) {
read_cb_ = BindToCurrentLoop(std::move(read_cb_));
- SatisfyRead(ABORTED, nullptr);
+ SatisfyRead(StatusCode::kAborted);
}
if (reset_cb_)
task_runner_->PostTask(FROM_HERE, std::move(reset_cb_));
@@ -189,20 +186,22 @@ void DecoderStream<StreamType>::Read(ReadCB read_cb) {
TRACE_EVENT_ASYNC_BEGIN0("media", GetReadTraceString<StreamType>(), this);
if (state_ == STATE_ERROR) {
read_cb_ = BindToCurrentLoop(std::move(read_cb));
- SatisfyRead(DECODE_ERROR, nullptr);
+ // TODO(crbug.com/1129662): Consider attaching a caused-by of the original
+ // error as well.
+ SatisfyRead(StatusCode::kDecoderStreamInErrorState);
return;
}
if (state_ == STATE_END_OF_STREAM && ready_outputs_.empty() &&
unprepared_outputs_.empty()) {
read_cb_ = BindToCurrentLoop(std::move(read_cb));
- SatisfyRead(OK, StreamTraits::CreateEOSOutput());
+ SatisfyRead(StreamTraits::CreateEOSOutput());
return;
}
if (!ready_outputs_.empty()) {
read_cb_ = BindToCurrentLoop(std::move(read_cb));
- SatisfyRead(OK, ready_outputs_.front());
+ SatisfyRead(ready_outputs_.front());
ready_outputs_.pop_front();
MaybePrepareAnotherOutput();
} else {
@@ -224,7 +223,7 @@ void DecoderStream<StreamType>::Reset(base::OnceClosure closure) {
if (read_cb_) {
read_cb_ = BindToCurrentLoop(std::move(read_cb_));
- SatisfyRead(ABORTED, nullptr);
+ SatisfyRead(StatusCode::kAborted);
}
ClearOutputs();
@@ -411,7 +410,7 @@ void DecoderStream<StreamType>::OnDecoderSelected(
media_log_->SetProperty<StreamTraits::kIsDecryptingDemuxerStream>(
!!decrypting_demuxer_stream_);
media_log_->SetProperty<StreamTraits::kDecoderName>(
- decoder_->GetDisplayName());
+ decoder_->GetDecoderType());
media_log_->SetProperty<StreamTraits::kIsPlatformDecoder>(
decoder_->IsPlatformDecoder());
@@ -440,12 +439,11 @@ void DecoderStream<StreamType>::OnDecoderSelected(
}
template <DemuxerStream::Type StreamType>
-void DecoderStream<StreamType>::SatisfyRead(ReadStatus status,
- scoped_refptr<Output> output) {
+void DecoderStream<StreamType>::SatisfyRead(ReadResult result) {
DCHECK(read_cb_);
TRACE_EVENT_ASYNC_END1("media", GetReadTraceString<StreamType>(), this,
- "status", GetStatusString<StreamType>(status));
- std::move(read_cb_).Run(status, std::move(output));
+ "status", GetStatusString(result.code()));
+ std::move(read_cb_).Run(std::move(result));
}
template <DemuxerStream::Type StreamType>
@@ -505,7 +503,7 @@ void DecoderStream<StreamType>::DecodeInternal(
std::move(buffer),
base::BindOnce(&DecoderStream<StreamType>::OnDecodeDone,
fallback_weak_factory_.GetWeakPtr(), buffer_size,
- decoding_eos_, base::Passed(&trace_event)));
+ decoding_eos_, std::move(trace_event)));
}
template <DemuxerStream::Type StreamType>
@@ -567,7 +565,7 @@ void DecoderStream<StreamType>::OnDecodeDone(
if (end_of_stream) {
state_ = STATE_END_OF_STREAM;
if (ready_outputs_.empty() && unprepared_outputs_.empty() && read_cb_)
- SatisfyRead(OK, StreamTraits::CreateEOSOutput());
+ SatisfyRead(StreamTraits::CreateEOSOutput());
return;
}
@@ -594,14 +592,14 @@ void DecoderStream<StreamType>::OnDecodeDone(
state_ = STATE_REINITIALIZING_DECODER;
SelectDecoder();
} else {
- media_log_->NotifyError(std::move(status));
+ media_log_->NotifyError(status);
MEDIA_LOG(ERROR, media_log_)
<< GetStreamTypeString() << " decode error!";
state_ = STATE_ERROR;
ClearOutputs();
if (read_cb_)
- SatisfyRead(DECODE_ERROR, nullptr);
+ SatisfyRead(std::move(status));
}
return;
}
@@ -653,7 +651,7 @@ void DecoderStream<StreamType>::OnDecodeOutputReady(
// If |ready_outputs_| was non-empty, the read would have already been
// satisifed by Read().
DCHECK(ready_outputs_.empty());
- SatisfyRead(OK, std::move(output));
+ SatisfyRead(std::move(output));
return;
}
@@ -743,7 +741,7 @@ void DecoderStream<StreamType>::OnBufferReady(
pending_buffers_.clear();
ClearOutputs();
if (read_cb_)
- SatisfyRead(DECODE_ERROR, nullptr);
+ SatisfyRead(StatusCode::kDecoderStreamDemuxerError);
}
// Decoding has been stopped.
@@ -819,7 +817,7 @@ void DecoderStream<StreamType>::OnBufferReady(
if (status == DemuxerStream::kAborted) {
if (read_cb_)
- SatisfyRead(DEMUXER_READ_ABORTED, nullptr);
+ SatisfyRead(StatusCode::kAborted);
return;
}
@@ -862,7 +860,7 @@ void DecoderStream<StreamType>::CompleteDecoderReinitialization(bool success) {
if (state_ == STATE_ERROR) {
MEDIA_LOG(ERROR, media_log_)
<< GetStreamTypeString() << " decoder reinitialization failed";
- SatisfyRead(DECODE_ERROR, nullptr);
+ SatisfyRead(StatusCode::kDecoderStreamReinitFailed);
return;
}
@@ -981,7 +979,7 @@ void DecoderStream<StreamType>::OnPreparedOutputReady(
if (!read_cb_)
ready_outputs_.emplace_back(std::move(output));
else
- SatisfyRead(OK, std::move(output));
+ SatisfyRead(std::move(output));
MaybePrepareAnotherOutput();
diff --git a/chromium/media/filters/decoder_stream.h b/chromium/media/filters/decoder_stream.h
index 0d881689024..6fe5739c8d3 100644
--- a/chromium/media/filters/decoder_stream.h
+++ b/chromium/media/filters/decoder_stream.h
@@ -14,7 +14,7 @@
#include "base/containers/circular_deque.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "media/base/audio_decoder.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/demuxer_stream.h"
@@ -46,13 +46,6 @@ class MEDIA_EXPORT DecoderStream {
using Output = typename StreamTraits::OutputType;
using DecoderConfig = typename StreamTraits::DecoderConfigType;
- enum ReadStatus {
- OK, // Everything went as planned.
- ABORTED, // Read aborted due to Reset() during pending read.
- DEMUXER_READ_ABORTED, // Demuxer returned aborted read.
- DECODE_ERROR, // Decoder returned decode error.
- };
-
// Callback to create a list of decoders.
using CreateDecodersCB =
base::RepeatingCallback<std::vector<std::unique_ptr<Decoder>>()>;
@@ -61,7 +54,8 @@ class MEDIA_EXPORT DecoderStream {
using InitCB = base::OnceCallback<void(bool success)>;
// Indicates completion of a DecoderStream read.
- using ReadCB = base::OnceCallback<void(ReadStatus, scoped_refptr<Output>)>;
+ using ReadResult = StatusOr<scoped_refptr<Output>>;
+ using ReadCB = base::OnceCallback<void(ReadResult)>;
DecoderStream(std::unique_ptr<DecoderStreamTraits<StreamType>> traits,
scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -131,9 +125,10 @@ class MEDIA_EXPORT DecoderStream {
config_change_observer_cb_ = config_change_observer;
}
- // Allows tests to keep track the currently selected decoder.
+ // Allow interested folks to keep track the currently selected decoder. The
+ // provided decoder is valid only during the scope of the callback.
using DecoderChangeObserverCB = base::RepeatingCallback<void(Decoder*)>;
- void set_decoder_change_observer_for_testing(
+ void set_decoder_change_observer(
DecoderChangeObserverCB decoder_change_observer_cb) {
decoder_change_observer_cb_ = std::move(decoder_change_observer_cb);
}
@@ -149,7 +144,7 @@ class MEDIA_EXPORT DecoderStream {
bool is_demuxer_read_pending() const { return pending_demuxer_read_; }
DecoderSelector<StreamType>& GetDecoderSelectorForTesting(
- util::PassKey<class VideoDecoderStreamTest>) {
+ base::PassKey<class VideoDecoderStreamTest>) {
return decoder_selector_;
}
@@ -185,8 +180,8 @@ class MEDIA_EXPORT DecoderStream {
std::unique_ptr<Decoder> selected_decoder,
std::unique_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream);
- // Satisfy pending |read_cb_| with |status| and |output|.
- void SatisfyRead(ReadStatus status, scoped_refptr<Output> output);
+ // Satisfy pending |read_cb_| with |result|.
+ void SatisfyRead(ReadResult result);
// Decodes |buffer| and returns the result via OnDecodeOutputReady().
// Saves |buffer| into |pending_buffers_| if appropriate.
diff --git a/chromium/media/filters/decoder_stream_traits.cc b/chromium/media/filters/decoder_stream_traits.cc
index c9e20bfd654..1222c802007 100644
--- a/chromium/media/filters/decoder_stream_traits.cc
+++ b/chromium/media/filters/decoder_stream_traits.cc
@@ -48,7 +48,9 @@ void DecoderStreamTraits<DemuxerStream::AUDIO>::SetIsDecryptingDemuxerStream(
DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
MediaLog* media_log,
ChannelLayout initial_hw_layout)
- : media_log_(media_log), initial_hw_layout_(initial_hw_layout) {}
+ : media_log_(media_log), initial_hw_layout_(initial_hw_layout) {
+ weak_this_ = weak_factory_.GetWeakPtr();
+}
DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderConfigType
DecoderStreamTraits<DemuxerStream::AUDIO>::GetDecoderConfig(
@@ -80,9 +82,24 @@ void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
OnConfigChanged(config);
config_ = config;
- stats_.audio_decoder_info.decoder_name = decoder->GetDisplayName();
- decoder->Initialize(config, cdm_context, std::move(init_cb), output_cb,
- waiting_cb);
+ stats_.audio_decoder_info.decoder_type = AudioDecoderType::kUnknown;
+ // Both |this| and |decoder| are owned by a DecoderSelector and will stay
+ // alive at least until |init_cb| is finished executing.
+ decoder->Initialize(
+ config, cdm_context,
+ base::BindOnce(
+ &DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecoderInitialized,
+ weak_this_, base::Unretained(decoder), std::move(init_cb)),
+ output_cb, waiting_cb);
+}
+
+void DecoderStreamTraits<DemuxerStream::AUDIO>::OnDecoderInitialized(
+ DecoderType* decoder,
+ InitCB cb,
+ Status result) {
+ if (result.is_ok())
+ stats_.audio_decoder_info.decoder_type = decoder->GetDecoderType();
+ std::move(cb).Run(result);
}
void DecoderStreamTraits<DemuxerStream::AUDIO>::OnStreamReset(
@@ -147,7 +164,9 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::SetIsDecryptingDemuxerStream(
DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderStreamTraits(
MediaLog* media_log)
// Randomly selected number of samples to keep.
- : keyframe_distance_average_(16) {}
+ : keyframe_distance_average_(16) {
+ weak_this_ = weak_factory_.GetWeakPtr();
+}
DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderConfigType
DecoderStreamTraits<DemuxerStream::VIDEO>::GetDecoderConfig(
@@ -181,10 +200,25 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
const OutputCB& output_cb,
const WaitingCB& waiting_cb) {
DCHECK(config.IsValidConfig());
- stats_.video_decoder_info.decoder_name = decoder->GetDisplayName();
- DVLOG(2) << stats_.video_decoder_info.decoder_name;
- decoder->Initialize(config, low_delay, cdm_context, std::move(init_cb),
- output_cb, waiting_cb);
+ stats_.video_decoder_info.decoder_type = VideoDecoderType::kUnknown;
+ DVLOG(2) << decoder->GetDisplayName();
+ // |decoder| is owned by a DecoderSelector and will stay
+ // alive at least until |init_cb| is finished executing.
+ decoder->Initialize(
+ config, low_delay, cdm_context,
+ base::BindOnce(
+ &DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized,
+ weak_this_, base::Unretained(decoder), std::move(init_cb)),
+ output_cb, waiting_cb);
+}
+
+void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecoderInitialized(
+ DecoderType* decoder,
+ InitCB cb,
+ Status result) {
+ if (result.is_ok())
+ stats_.video_decoder_info.decoder_type = decoder->GetDecoderType();
+ std::move(cb).Run(result);
}
void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
@@ -234,8 +268,8 @@ PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
return PostDecodeAction::DELIVER;
// Add a timestamp here to enable buffering delay measurements down the line.
- buffer->metadata()->decode_begin_time = it->second.decode_begin_time;
- buffer->metadata()->decode_end_time = base::TimeTicks::Now();
+ buffer->metadata().decode_begin_time = it->second.decode_begin_time;
+ buffer->metadata().decode_end_time = base::TimeTicks::Now();
auto action = it->second.should_drop ? PostDecodeAction::DROP
: PostDecodeAction::DELIVER;
@@ -243,7 +277,7 @@ PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
// Provide duration information to help the rendering algorithm on the very
// first and very last frames.
if (it->second.duration != kNoTimestamp)
- buffer->metadata()->frame_duration = it->second.duration;
+ buffer->metadata().frame_duration = it->second.duration;
// We erase from the beginning onward to our target frame since frames should
// be returned in presentation order. It's possible to accumulate entries in
@@ -255,12 +289,12 @@ PostDecodeAction DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecodeDone(
void DecoderStreamTraits<DemuxerStream::VIDEO>::OnOutputReady(
OutputType* buffer) {
- if (!buffer->metadata()->decode_begin_time.has_value())
+ if (!buffer->metadata().decode_begin_time.has_value())
return;
// Tag buffer with elapsed time since creation.
- buffer->metadata()->processing_time =
- base::TimeTicks::Now() - *buffer->metadata()->decode_begin_time;
+ buffer->metadata().processing_time =
+ base::TimeTicks::Now() - *buffer->metadata().decode_begin_time;
}
} // namespace media
diff --git a/chromium/media/filters/decoder_stream_traits.h b/chromium/media/filters/decoder_stream_traits.h
index 66fe7cd85e9..08aa2112881 100644
--- a/chromium/media/filters/decoder_stream_traits.h
+++ b/chromium/media/filters/decoder_stream_traits.h
@@ -65,6 +65,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> {
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb);
+ void OnDecoderInitialized(DecoderType* decoder, InitCB cb, Status status);
DecoderConfigType GetDecoderConfig(DemuxerStream* stream);
void OnDecode(const DecoderBuffer& buffer);
PostDecodeAction OnDecodeDone(OutputType* buffer);
@@ -84,6 +85,10 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> {
ChannelLayout initial_hw_layout_;
PipelineStatistics stats_;
AudioDecoderConfig config_;
+
+ base::WeakPtr<DecoderStreamTraits<DemuxerStream::AUDIO>> weak_this_;
+ base::WeakPtrFactory<DecoderStreamTraits<DemuxerStream::AUDIO>> weak_factory_{
+ this};
};
template <>
@@ -118,6 +123,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb);
+ void OnDecoderInitialized(DecoderType* decoder, InitCB cb, Status status);
void OnDecode(const DecoderBuffer& buffer);
PostDecodeAction OnDecodeDone(OutputType* buffer);
void OnStreamReset(DemuxerStream* stream);
@@ -136,6 +142,10 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
base::flat_map<base::TimeDelta, FrameMetadata> frame_metadata_;
PipelineStatistics stats_;
+
+ base::WeakPtr<DecoderStreamTraits<DemuxerStream::VIDEO>> weak_this_;
+ base::WeakPtrFactory<DecoderStreamTraits<DemuxerStream::VIDEO>> weak_factory_{
+ this};
};
} // namespace media
diff --git a/chromium/media/filters/decrypting_audio_decoder.cc b/chromium/media/filters/decrypting_audio_decoder.cc
index e42c00d8c6a..9415f532058 100644
--- a/chromium/media/filters/decrypting_audio_decoder.cc
+++ b/chromium/media/filters/decrypting_audio_decoder.cc
@@ -46,6 +46,10 @@ std::string DecryptingAudioDecoder::GetDisplayName() const {
return "DecryptingAudioDecoder";
}
+AudioDecoderType DecryptingAudioDecoder::GetDecoderType() const {
+ return AudioDecoderType::kDecrypting;
+}
+
void DecryptingAudioDecoder::Initialize(const AudioDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb,
diff --git a/chromium/media/filters/decrypting_audio_decoder.h b/chromium/media/filters/decrypting_audio_decoder.h
index aff41e2c9b7..9c77c521e1f 100644
--- a/chromium/media/filters/decrypting_audio_decoder.h
+++ b/chromium/media/filters/decrypting_audio_decoder.h
@@ -42,6 +42,7 @@ class MEDIA_EXPORT DecryptingAudioDecoder : public AudioDecoder {
// Decoder implementation
bool SupportsDecryption() const override;
+ AudioDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
// AudioDecoder implementation.
diff --git a/chromium/media/filters/decrypting_audio_decoder_unittest.cc b/chromium/media/filters/decrypting_audio_decoder_unittest.cc
index b88ec863f1f..c796c8f302d 100644
--- a/chromium/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/chromium/media/filters/decrypting_audio_decoder_unittest.cc
@@ -12,6 +12,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/gmock_callback_support.h"
+#include "base/test/gmock_move_support.h"
#include "base/test/task_environment.h"
#include "media/base/audio_buffer.h"
#include "media/base/decoder_buffer.h"
@@ -23,12 +24,10 @@
#include "media/filters/decrypting_audio_decoder.h"
#include "testing/gmock/include/gmock/gmock.h"
-using ::base::test::RunCallback;
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::AtMost;
using ::testing::Return;
-using ::testing::SaveArg;
using ::testing::StrictMock;
namespace media {
@@ -148,20 +147,21 @@ class DecryptingAudioDecoderTest : public testing::Test {
// Helper function to simulate the decrypting and decoding process in the
// |decryptor_| with a decoding delay of kDecodingDelay buffers.
void DecryptAndDecodeAudio(scoped_refptr<DecoderBuffer> encrypted,
- const Decryptor::AudioDecodeCB& audio_decode_cb) {
+ Decryptor::AudioDecodeCB audio_decode_cb) {
num_decrypt_and_decode_calls_++;
if (!encrypted->end_of_stream())
num_frames_in_decryptor_++;
if (num_decrypt_and_decode_calls_ <= kDecodingDelay ||
num_frames_in_decryptor_ == 0) {
- audio_decode_cb.Run(Decryptor::kNeedMoreData, Decryptor::AudioFrames());
+ std::move(audio_decode_cb)
+ .Run(Decryptor::kNeedMoreData, Decryptor::AudioFrames());
return;
}
num_frames_in_decryptor_--;
- audio_decode_cb.Run(Decryptor::kSuccess,
- Decryptor::AudioFrames(1, decoded_frame_));
+ std::move(audio_decode_cb)
+ .Run(Decryptor::kSuccess, Decryptor::AudioFrames(1, decoded_frame_));
}
// Sets up expectations and actions to put DecryptingAudioDecoder in an
@@ -189,7 +189,7 @@ class DecryptingAudioDecoderTest : public testing::Test {
void EnterPendingDecodeState() {
EXPECT_TRUE(!pending_audio_decode_cb_);
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
- .WillOnce(SaveArg<1>(&pending_audio_decode_cb_));
+ .WillOnce(MoveArg<1>(&pending_audio_decode_cb_));
decoder_->Decode(encrypted_buffer_,
base::BindOnce(&DecryptingAudioDecoderTest::DecodeDone,
@@ -203,7 +203,7 @@ class DecryptingAudioDecoderTest : public testing::Test {
void EnterWaitingForKeyState() {
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames()));
+ RunOnceCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames()));
EXPECT_CALL(*this, OnWaiting(WaitingReason::kNoDecryptionKey));
decoder_->Decode(encrypted_buffer_,
base::BindOnce(&DecryptingAudioDecoderTest::DecodeDone,
@@ -326,7 +326,7 @@ TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_DecodeError) {
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kError, Decryptor::AudioFrames()));
+ RunOnceCallback<1>(Decryptor::kError, Decryptor::AudioFrames()));
DecodeAndExpect(encrypted_buffer_, DecodeStatus::DECODE_ERROR);
}
@@ -347,7 +347,7 @@ TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFrames) {
decoded_frame_list_.push_back(frame_b);
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillOnce(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillOnce(RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
EXPECT_CALL(*this, FrameReady(frame_a));
@@ -413,7 +413,8 @@ TEST_F(DecryptingAudioDecoderTest, KeyAdded_DuringWaitingForKey) {
EnterWaitingForKeyState();
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillRepeatedly(
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
@@ -427,7 +428,8 @@ TEST_F(DecryptingAudioDecoderTest, KeyAdded_DruingPendingDecode) {
EnterPendingDecodeState();
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillRepeatedly(
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
// The audio decode callback is returned after the correct decryption key is
diff --git a/chromium/media/filters/decrypting_video_decoder.cc b/chromium/media/filters/decrypting_video_decoder.cc
index 43601b56c5d..548d9ba61b4 100644
--- a/chromium/media/filters/decrypting_video_decoder.cc
+++ b/chromium/media/filters/decrypting_video_decoder.cc
@@ -28,6 +28,10 @@ DecryptingVideoDecoder::DecryptingVideoDecoder(
DETACH_FROM_SEQUENCE(sequence_checker_);
}
+VideoDecoderType DecryptingVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kDecrypting;
+}
+
std::string DecryptingVideoDecoder::GetDisplayName() const {
return kDecoderName;
}
@@ -298,7 +302,7 @@ void DecryptingVideoDecoder::DeliverFrame(Decryptor::Status status,
CHECK(frame);
// Frame returned with kSuccess should not be an end-of-stream frame.
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
// If color space is not set, use the color space in the |config_|.
if (!frame->ColorSpace().IsValid()) {
diff --git a/chromium/media/filters/decrypting_video_decoder.h b/chromium/media/filters/decrypting_video_decoder.h
index 6f7c92402ec..e8715db88be 100644
--- a/chromium/media/filters/decrypting_video_decoder.h
+++ b/chromium/media/filters/decrypting_video_decoder.h
@@ -41,6 +41,7 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder {
bool SupportsDecryption() const override;
// VideoDecoder implementation.
+ VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
diff --git a/chromium/media/filters/decrypting_video_decoder_unittest.cc b/chromium/media/filters/decrypting_video_decoder_unittest.cc
index 525fdb247f5..82cc59ed390 100644
--- a/chromium/media/filters/decrypting_video_decoder_unittest.cc
+++ b/chromium/media/filters/decrypting_video_decoder_unittest.cc
@@ -12,6 +12,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/gmock_callback_support.h"
+#include "base/test/gmock_move_support.h"
#include "base/test/task_environment.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
@@ -22,12 +23,10 @@
#include "media/filters/decrypting_video_decoder.h"
#include "testing/gmock/include/gmock/gmock.h"
-using ::base::test::RunCallback;
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
-using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::WithArg;
@@ -135,20 +134,20 @@ class DecryptingVideoDecoderTest : public testing::Test {
// Helper function to simulate the decrypting and decoding process in the
// |decryptor_| with a decoding delay of kDecodingDelay buffers.
void DecryptAndDecodeVideo(scoped_refptr<DecoderBuffer> encrypted,
- const Decryptor::VideoDecodeCB& video_decode_cb) {
+ Decryptor::VideoDecodeCB video_decode_cb) {
num_decrypt_and_decode_calls_++;
if (!encrypted->end_of_stream())
num_frames_in_decryptor_++;
if (num_decrypt_and_decode_calls_ <= kDecodingDelay ||
num_frames_in_decryptor_ == 0) {
- video_decode_cb.Run(Decryptor::kNeedMoreData,
- scoped_refptr<VideoFrame>());
+ std::move(video_decode_cb)
+ .Run(Decryptor::kNeedMoreData, scoped_refptr<VideoFrame>());
return;
}
num_frames_in_decryptor_--;
- video_decode_cb.Run(Decryptor::kSuccess, decoded_video_frame_);
+ std::move(video_decode_cb).Run(Decryptor::kSuccess, decoded_video_frame_);
}
// Sets up expectations and actions to put DecryptingVideoDecoder in an
@@ -176,7 +175,7 @@ class DecryptingVideoDecoderTest : public testing::Test {
void EnterPendingDecodeState() {
EXPECT_TRUE(!pending_video_decode_cb_);
EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(encrypted_buffer_, _))
- .WillOnce(SaveArg<1>(&pending_video_decode_cb_));
+ .WillOnce(MoveArg<1>(&pending_video_decode_cb_));
decoder_->Decode(encrypted_buffer_,
base::BindOnce(&DecryptingVideoDecoderTest::DecodeDone,
@@ -189,7 +188,8 @@ class DecryptingVideoDecoderTest : public testing::Test {
void EnterWaitingForKeyState() {
EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, null_video_frame_));
+ .WillRepeatedly(
+ RunOnceCallback<1>(Decryptor::kNoKey, null_video_frame_));
EXPECT_CALL(*this, OnWaiting(WaitingReason::kNoDecryptionKey));
decoder_->Decode(encrypted_buffer_,
base::BindOnce(&DecryptingVideoDecoderTest::DecodeDone,
@@ -319,8 +319,8 @@ TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_DecodeError) {
Initialize();
EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kError,
- scoped_refptr<VideoFrame>(nullptr)));
+ .WillRepeatedly(RunOnceCallback<1>(Decryptor::kError,
+ scoped_refptr<VideoFrame>(nullptr)));
DecodeAndExpectError(encrypted_buffer_);
@@ -343,7 +343,7 @@ TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringWaitingForKey) {
EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
EXPECT_CALL(*this, FrameReady(decoded_video_frame_));
EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
@@ -358,7 +358,7 @@ TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringPendingDecode) {
EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_video_frame_));
EXPECT_CALL(*this, FrameReady(decoded_video_frame_));
EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
// The video decode callback is returned after the correct decryption key is
diff --git a/chromium/media/filters/demuxer_perftest.cc b/chromium/media/filters/demuxer_perftest.cc
index d444f4d06f9..3bb2619c3e8 100644
--- a/chromium/media/filters/demuxer_perftest.cc
+++ b/chromium/media/filters/demuxer_perftest.cc
@@ -45,10 +45,10 @@ class DemuxerHostImpl : public media::DemuxerHost {
DISALLOW_COPY_AND_ASSIGN(DemuxerHostImpl);
};
-static void QuitLoopWithStatus(base::Closure quit_cb,
+static void QuitLoopWithStatus(base::OnceClosure quit_cb,
media::PipelineStatus status) {
CHECK_EQ(status, media::PIPELINE_OK);
- quit_cb.Run();
+ std::move(quit_cb).Run();
}
static void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
@@ -81,7 +81,7 @@ class StreamReader {
private:
void OnReadDone(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const base::Closure& quit_when_idle_closure,
+ base::OnceClosure quit_when_idle_closure,
bool* end_of_stream,
base::TimeDelta* timestamp,
media::DemuxerStream::Status status,
@@ -139,7 +139,7 @@ bool StreamReader::IsDone() {
void StreamReader::OnReadDone(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const base::Closure& quit_when_idle_closure,
+ base::OnceClosure quit_when_idle_closure,
bool* end_of_stream,
base::TimeDelta* timestamp,
media::DemuxerStream::Status status,
@@ -148,7 +148,7 @@ void StreamReader::OnReadDone(
CHECK(buffer);
*end_of_stream = buffer->end_of_stream();
*timestamp = *end_of_stream ? media::kNoTimestamp : buffer->timestamp();
- task_runner->PostTask(FROM_HERE, quit_when_idle_closure);
+ task_runner->PostTask(FROM_HERE, std::move(quit_when_idle_closure));
}
int StreamReader::GetNextStreamIndexToRead() {
diff --git a/chromium/media/filters/fake_video_decoder.cc b/chromium/media/filters/fake_video_decoder.cc
index e2f4726f28f..4e8593fd530 100644
--- a/chromium/media/filters/fake_video_decoder.cc
+++ b/chromium/media/filters/fake_video_decoder.cc
@@ -68,6 +68,10 @@ std::string FakeVideoDecoder::GetDisplayName() const {
return decoder_name_;
}
+VideoDecoderType FakeVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kUnknown;
+}
+
void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
diff --git a/chromium/media/filters/fake_video_decoder.h b/chromium/media/filters/fake_video_decoder.h
index 898f4dab778..45e920a9496 100644
--- a/chromium/media/filters/fake_video_decoder.h
+++ b/chromium/media/filters/fake_video_decoder.h
@@ -49,6 +49,7 @@ class FakeVideoDecoder : public VideoDecoder {
bool SupportsDecryption() const override;
bool IsPlatformDecoder() const override;
std::string GetDisplayName() const override;
+ VideoDecoderType GetDecoderType() const override;
// VideoDecoder implementation
void Initialize(const VideoDecoderConfig& config,
diff --git a/chromium/media/filters/fake_video_decoder_unittest.cc b/chromium/media/filters/fake_video_decoder_unittest.cc
index 49130158ce1..58baa499a53 100644
--- a/chromium/media/filters/fake_video_decoder_unittest.cc
+++ b/chromium/media/filters/fake_video_decoder_unittest.cc
@@ -91,7 +91,7 @@ class FakeVideoDecoderTest
}
void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
last_decoded_frame_ = std::move(frame);
num_decoded_frames_++;
}
diff --git a/chromium/media/filters/ffmpeg_audio_decoder.cc b/chromium/media/filters/ffmpeg_audio_decoder.cc
index e5daea40328..7ff037ac847 100644
--- a/chromium/media/filters/ffmpeg_audio_decoder.cc
+++ b/chromium/media/filters/ffmpeg_audio_decoder.cc
@@ -69,6 +69,10 @@ std::string FFmpegAudioDecoder::GetDisplayName() const {
return "FFmpegAudioDecoder";
}
+AudioDecoderType FFmpegAudioDecoder::GetDecoderType() const {
+ return AudioDecoderType::kFFmpeg;
+}
+
void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config,
CdmContext* /* cdm_context */,
InitCB init_cb,
diff --git a/chromium/media/filters/ffmpeg_audio_decoder.h b/chromium/media/filters/ffmpeg_audio_decoder.h
index 2111b89a797..5b3d20380e7 100644
--- a/chromium/media/filters/ffmpeg_audio_decoder.h
+++ b/chromium/media/filters/ffmpeg_audio_decoder.h
@@ -40,6 +40,7 @@ class MEDIA_EXPORT FFmpegAudioDecoder : public AudioDecoder {
~FFmpegAudioDecoder() override;
// AudioDecoder implementation.
+ AudioDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const AudioDecoderConfig& config,
CdmContext* cdm_context,
diff --git a/chromium/media/filters/ffmpeg_demuxer.cc b/chromium/media/filters/ffmpeg_demuxer.cc
index fa39c5698ed..5d8134ceaa6 100644
--- a/chromium/media/filters/ffmpeg_demuxer.cc
+++ b/chromium/media/filters/ffmpeg_demuxer.cc
@@ -12,6 +12,7 @@
#include "base/base64.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
@@ -32,6 +33,7 @@
#include "media/base/decrypt_config.h"
#include "media/base/demuxer_memory_limit.h"
#include "media/base/limits.h"
+#include "media/base/media_switches.h"
#include "media/base/media_tracks.h"
#include "media/base/media_types.h"
#include "media/base/sample_rates.h"
@@ -214,6 +216,17 @@ std::unique_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create(
std::unique_ptr<AudioDecoderConfig> audio_config;
std::unique_ptr<VideoDecoderConfig> video_config;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ if (base::FeatureList::IsEnabled(kDeprecateLowUsageCodecs)) {
+ const auto codec_id = stream->codecpar->codec_id;
+ if (codec_id == AV_CODEC_ID_AMR_NB || codec_id == AV_CODEC_ID_AMR_WB ||
+ codec_id == AV_CODEC_ID_GSM_MS) {
+ MEDIA_LOG(ERROR, media_log) << "AMR and GSM are deprecated on ChromeOS.";
+ return nullptr;
+ }
+ }
+#endif
+
if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_config = std::make_unique<AudioDecoderConfig>();
diff --git a/chromium/media/filters/ffmpeg_demuxer_unittest.cc b/chromium/media/filters/ffmpeg_demuxer_unittest.cc
index 5bdd717becc..698990ed696 100644
--- a/chromium/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/chromium/media/filters/ffmpeg_demuxer_unittest.cc
@@ -779,7 +779,7 @@ TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOpusDiscard_Sync) {
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(FFmpegDemuxerTest, TestAudioNegativeTimestamps) {
// Note: This test will _crash_ the browser if negative timestamp
// values are skipped, since this file is heavily truncated to avoid
@@ -795,7 +795,7 @@ TEST_F(FFmpegDemuxerTest, TestAudioNegativeTimestamps) {
Read(audio, FROM_HERE, 104, 77619, true);
Read(audio, FROM_HERE, 104, 103492, true);
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Similar to the test above, but using an opus clip plus h264 b-frames to
// ensure we don't apply chained ogg workarounds to other content.
@@ -1653,10 +1653,10 @@ TEST_F(FFmpegDemuxerTest, Seek_FallbackToDisabledAudioStream) {
}
namespace {
-void QuitLoop(base::Closure quit_closure,
+void QuitLoop(base::OnceClosure quit_closure,
DemuxerStream::Type type,
const std::vector<DemuxerStream*>& streams) {
- quit_closure.Run();
+ std::move(quit_closure).Run();
}
void DisableAndEnableDemuxerTracks(
diff --git a/chromium/media/filters/ffmpeg_glue_unittest.cc b/chromium/media/filters/ffmpeg_glue_unittest.cc
index 53db86c0dc8..e37437d683b 100644
--- a/chromium/media/filters/ffmpeg_glue_unittest.cc
+++ b/chromium/media/filters/ffmpeg_glue_unittest.cc
@@ -316,7 +316,7 @@ TEST_F(FFmpegGlueContainerTest, AAC) {
ExpectContainer(container_names::CONTAINER_AAC);
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(FFmpegGlueContainerTest, AVI) {
InitializeAndOpen("bear.avi");
ExpectContainer(container_names::CONTAINER_AVI);
@@ -326,7 +326,7 @@ TEST_F(FFmpegGlueContainerTest, AMR) {
InitializeAndOpen("bear.amr");
ExpectContainer(container_names::CONTAINER_AMR);
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
// Probe something unsupported to ensure we fall back to the our internal guess.
diff --git a/chromium/media/filters/ffmpeg_video_decoder.cc b/chromium/media/filters/ffmpeg_video_decoder.cc
index d703189571a..6e4abe2ae76 100644
--- a/chromium/media/filters/ffmpeg_video_decoder.cc
+++ b/chromium/media/filters/ffmpeg_video_decoder.cc
@@ -83,6 +83,30 @@ bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) {
return avcodec_find_decoder(VideoCodecToCodecID(codec)) != nullptr;
}
+// static
+SupportedVideoDecoderConfigs FFmpegVideoDecoder::SupportedConfigsForWebRTC() {
+ SupportedVideoDecoderConfigs supported_configs;
+
+ if (IsCodecSupported(kCodecH264)) {
+ supported_configs.emplace_back(/*profile_min=*/H264PROFILE_BASELINE,
+ /*profile_max=*/H264PROFILE_HIGH,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false);
+ }
+ if (IsCodecSupported(kCodecVP8)) {
+ supported_configs.emplace_back(/*profile_min=*/VP8PROFILE_ANY,
+ /*profile_max=*/VP8PROFILE_ANY,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false);
+ }
+
+ return supported_configs;
+}
+
FFmpegVideoDecoder::FFmpegVideoDecoder(MediaLog* media_log)
: media_log_(media_log), state_(kUninitialized), decode_nalus_(false) {
DVLOG(1) << __func__;
@@ -161,6 +185,13 @@ int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context,
if (codec_context->color_range == AVCOL_RANGE_JPEG) {
video_frame->set_color_space(gfx::ColorSpace::CreateJpeg());
}
+ } else if (codec_context->codec_id == AV_CODEC_ID_H264 &&
+ codec_context->colorspace == AVCOL_SPC_RGB &&
+ format == PIXEL_FORMAT_I420) {
+ // Some H.264 videos contain a VUI that specifies a color matrix of GBR,
+ // when they are actually ordinary YUV. Only 4:2:0 formats are checked,
+ // because GBR is reasonable for 4:4:4 content. See crbug.com/1067377.
+ video_frame->set_color_space(gfx::ColorSpace::CreateREC709());
} else if (codec_context->color_primaries != AVCOL_PRI_UNSPECIFIED ||
codec_context->color_trc != AVCOL_TRC_UNSPECIFIED ||
codec_context->colorspace != AVCOL_SPC_UNSPECIFIED) {
@@ -196,6 +227,10 @@ int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context,
return 0;
}
+VideoDecoderType FFmpegVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kFFmpeg;
+}
+
std::string FFmpegVideoDecoder::GetDisplayName() const {
return "FFmpegVideoDecoder";
}
@@ -359,7 +394,7 @@ bool FFmpegVideoDecoder::OnNewFrame(AVFrame* frame) {
reinterpret_cast<VideoFrame*>(av_buffer_get_opaque(frame->buf[0]));
video_frame->set_timestamp(
base::TimeDelta::FromMicroseconds(frame->reordered_opaque));
- video_frame->metadata()->power_efficient = false;
+ video_frame->metadata().power_efficient = false;
output_cb_.Run(video_frame);
return true;
}
diff --git a/chromium/media/filters/ffmpeg_video_decoder.h b/chromium/media/filters/ffmpeg_video_decoder.h
index 4ea30459b48..de1ff5390d0 100644
--- a/chromium/media/filters/ffmpeg_video_decoder.h
+++ b/chromium/media/filters/ffmpeg_video_decoder.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame_pool.h"
@@ -29,6 +30,7 @@ class MediaLog;
class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
public:
static bool IsCodecSupported(VideoCodec codec);
+ static SupportedVideoDecoderConfigs SupportedConfigsForWebRTC();
explicit FFmpegVideoDecoder(MediaLog* media_log);
~FFmpegVideoDecoder() override;
@@ -38,6 +40,7 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
void set_decode_nalus(bool decode_nalus) { decode_nalus_ = decode_nalus; }
// VideoDecoder implementation.
+ VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
diff --git a/chromium/media/filters/ffmpeg_video_decoder_unittest.cc b/chromium/media/filters/ffmpeg_video_decoder_unittest.cc
index 599fb12c7fe..3a07a387ad1 100644
--- a/chromium/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/chromium/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -197,7 +197,7 @@ class FFmpegVideoDecoderTest : public testing::Test {
}
void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
output_frames_.push_back(std::move(frame));
}
diff --git a/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc b/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc
index d17b79cb657..76149fddb7b 100644
--- a/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc
+++ b/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -123,7 +123,7 @@ class OutputMailbox {
coded_size, visible_rect, natural_size, timestamp);
// Request a fence we'll wait on before reusing the buffer.
- frame->metadata()->read_lock_fences_enabled = true;
+ frame->metadata().read_lock_fences_enabled = true;
return frame;
}
@@ -134,7 +134,7 @@ class OutputMailbox {
// The mailbox is referenced by a VideoFrame. It will be deleted as soon
// as the frame is destroyed.
DCHECK(reuse_callback_);
- reuse_callback_ = base::Closure();
+ reuse_callback_ = base::OnceClosure();
} else {
delete this;
}
@@ -197,6 +197,7 @@ class FuchsiaVideoDecoder : public VideoDecoder,
bool IsPlatformDecoder() const override;
bool SupportsDecryption() const override;
std::string GetDisplayName() const override;
+ VideoDecoderType GetDecoderType() const override;
// VideoDecoder implementation.
void Initialize(const VideoDecoderConfig& config,
@@ -334,6 +335,7 @@ FuchsiaVideoDecoder::FuchsiaVideoDecoder(
enable_sw_decoding_(enable_sw_decoding),
use_overlays_for_video_(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseOverlaysForVideo)),
+ sysmem_allocator_("CrFuchsiaVideoDecoder"),
client_native_pixmap_factory_(ui::CreateClientNativePixmapFactoryOzone()),
weak_factory_(this) {
DCHECK(raster_context_provider_);
@@ -361,6 +363,10 @@ std::string FuchsiaVideoDecoder::GetDisplayName() const {
return "FuchsiaVideoDecoder";
}
+VideoDecoderType FuchsiaVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kFuchsia;
+}
+
void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
@@ -684,8 +690,9 @@ void FuchsiaVideoDecoder::SendInputPacket(
DCHECK(in_flight_input_packets_.find(packet.buffer_index()) ==
in_flight_input_packets_.end());
+ const size_t buffer_index = packet.buffer_index();
in_flight_input_packets_.insert_or_assign(
- packet.buffer_index(), InputDecoderPacket{std::move(packet)});
+ buffer_index, InputDecoderPacket{std::move(packet)});
}
void FuchsiaVideoDecoder::ProcessEndOfStream() {
@@ -765,14 +772,18 @@ void FuchsiaVideoDecoder::OnOutputConstraints(
fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
sysmem_allocator_.raw()->AllocateSharedCollection(
collection_token.NewRequest());
+ collection_token->SetName(100u, "ChromiumVideoDecoderOutput");
+ collection_token->SetDebugClientInfo("chromium_video_decoder", 0u);
// Create sysmem tokens for the gpu process and the codec.
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_codec.NewRequest());
+ collection_token_for_codec->SetDebugClientInfo("codec", 0u);
fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_gpu.NewRequest());
+ collection_token_for_gpu->SetDebugClientInfo("chromium_gpu", 0u);
// Convert the token to a BufferCollection connection.
sysmem_allocator_.raw()->BindSharedCollection(
@@ -944,11 +955,11 @@ void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet,
// codec may still decode on hardware even when |enable_sw_decoding_| is set
// (i.e. power_efficient flag would not be set correctly in that case). It
// doesn't matter because software decoders can be enabled only for tests.
- frame->metadata()->power_efficient = !enable_sw_decoding_;
+ frame->metadata().power_efficient = !enable_sw_decoding_;
// Allow this video frame to be promoted as an overlay, because it was
// registered with an ImagePipe.
- frame->metadata()->allow_overlay = use_overlays_for_video_;
+ frame->metadata().allow_overlay = use_overlays_for_video_;
output_cb_.Run(std::move(frame));
}
diff --git a/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc b/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
index 5e4c36998e3..2b319eae494 100644
--- a/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
+++ b/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
@@ -13,6 +13,7 @@
#include "base/containers/flat_set.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
+#include "base/process/process_handle.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/viz/common/gpu/raster_context_provider.h"
@@ -24,6 +25,7 @@
#include "media/base/video_decoder.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_memory_buffer.h"
namespace media {
@@ -40,6 +42,8 @@ class TestBufferCollection {
ZX_LOG(FATAL, status)
<< "The fuchsia.sysmem.Allocator channel was terminated.";
});
+ sysmem_allocator_->SetDebugClientInfo("CrTestBufferCollection",
+ base::GetCurrentProcId());
sysmem_allocator_->BindSharedCollection(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>(
@@ -212,8 +216,8 @@ class TestRasterContextProvider
TestRasterContextProvider(TestRasterContextProvider&) = delete;
TestRasterContextProvider& operator=(TestRasterContextProvider&) = delete;
- void SetOnDestroyedClosure(base::Closure on_destroyed) {
- on_destroyed_ = on_destroyed;
+ void SetOnDestroyedClosure(base::OnceClosure on_destroyed) {
+ on_destroyed_ = std::move(on_destroyed);
}
// viz::RasterContextProvider implementation;
@@ -277,7 +281,7 @@ class TestRasterContextProvider
TestSharedImageInterface shared_image_interface_;
viz::TestContextSupport gpu_context_support_;
- base::Closure on_destroyed_;
+ base::OnceClosure on_destroyed_;
};
} // namespace
diff --git a/chromium/media/filters/gav1_video_decoder.cc b/chromium/media/filters/gav1_video_decoder.cc
index 8e0e69c3aac..729c562c123 100644
--- a/chromium/media/filters/gav1_video_decoder.cc
+++ b/chromium/media/filters/gav1_video_decoder.cc
@@ -224,13 +224,23 @@ scoped_refptr<VideoFrame> FormatVideoFrame(
color_space = container_color_space;
frame->set_color_space(color_space.ToGfxColorSpace());
- frame->metadata()->power_efficient = false;
+ frame->metadata().power_efficient = false;
return frame;
}
} // namespace
+// static
+SupportedVideoDecoderConfigs Gav1VideoDecoder::SupportedConfigs() {
+ return {{/*profile_min=*/AV1PROFILE_PROFILE_MAIN,
+ /*profile_max=*/AV1PROFILE_PROFILE_HIGH,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false}};
+}
+
Gav1VideoDecoder::Gav1VideoDecoder(MediaLog* media_log,
OffloadState offload_state)
: media_log_(media_log),
@@ -247,6 +257,10 @@ std::string Gav1VideoDecoder::GetDisplayName() const {
return "Gav1VideoDecoder";
}
+VideoDecoderType Gav1VideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kGav1;
+}
+
void Gav1VideoDecoder::Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* /* cdm_context */,
diff --git a/chromium/media/filters/gav1_video_decoder.h b/chromium/media/filters/gav1_video_decoder.h
index 22cd0053923..b4e78e07f04 100644
--- a/chromium/media/filters/gav1_video_decoder.h
+++ b/chromium/media/filters/gav1_video_decoder.h
@@ -15,6 +15,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "media/base/media_export.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame_pool.h"
#include "media/filters/offloading_video_decoder.h"
@@ -28,6 +29,8 @@ class MediaLog;
class MEDIA_EXPORT Gav1VideoDecoder : public OffloadableVideoDecoder {
public:
+ static SupportedVideoDecoderConfigs SupportedConfigs();
+
explicit Gav1VideoDecoder(MediaLog* media_log,
OffloadState offload_state = OffloadState::kNormal);
~Gav1VideoDecoder() override;
@@ -36,6 +39,7 @@ class MEDIA_EXPORT Gav1VideoDecoder : public OffloadableVideoDecoder {
// VideoDecoder implementation.
std::string GetDisplayName() const override;
+ VideoDecoderType GetDecoderType() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
diff --git a/chromium/media/filters/gav1_video_decoder_unittest.cc b/chromium/media/filters/gav1_video_decoder_unittest.cc
index 4169f610d4f..33ccf13e2c4 100644
--- a/chromium/media/filters/gav1_video_decoder_unittest.cc
+++ b/chromium/media/filters/gav1_video_decoder_unittest.cc
@@ -194,7 +194,7 @@ class Gav1VideoDecoderTest : public testing::Test {
}
void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
output_frames_.push_back(std::move(frame));
}
diff --git a/chromium/media/filters/memory_data_source.h b/chromium/media/filters/memory_data_source.h
index 716cb776157..d78dee1530a 100644
--- a/chromium/media/filters/memory_data_source.h
+++ b/chromium/media/filters/memory_data_source.h
@@ -41,7 +41,10 @@ class MEDIA_EXPORT MemoryDataSource final : public DataSource {
const uint8_t* data_ = nullptr;
const size_t size_ = 0;
- bool is_stopped_ = false;
+ // Stop may be called from the render thread while this class is being used by
+ // the media thread. It's harmless if we fulfill a read after Stop() has been
+ // called, so an atomic without a lock is safe.
+ std::atomic<bool> is_stopped_{false};
DISALLOW_COPY_AND_ASSIGN(MemoryDataSource);
};
diff --git a/chromium/media/filters/offloading_video_decoder.cc b/chromium/media/filters/offloading_video_decoder.cc
index 242190f8009..c5379ebf0ec 100644
--- a/chromium/media/filters/offloading_video_decoder.cc
+++ b/chromium/media/filters/offloading_video_decoder.cc
@@ -75,6 +75,11 @@ OffloadingVideoDecoder::~OffloadingVideoDecoder() {
offload_task_runner_->DeleteSoon(FROM_HERE, std::move(helper_));
}
+VideoDecoderType OffloadingVideoDecoder::GetDecoderType() const {
+ // This call is expected to be static and safe to call from any thread.
+ return helper_->decoder()->GetDecoderType();
+}
+
std::string OffloadingVideoDecoder::GetDisplayName() const {
// This call is expected to be static and safe to call from any thread.
return helper_->decoder()->GetDisplayName();
diff --git a/chromium/media/filters/offloading_video_decoder.h b/chromium/media/filters/offloading_video_decoder.h
index 0ff14bb3d45..5caf47895f8 100644
--- a/chromium/media/filters/offloading_video_decoder.h
+++ b/chromium/media/filters/offloading_video_decoder.h
@@ -88,6 +88,7 @@ class MEDIA_EXPORT OffloadingVideoDecoder : public VideoDecoder {
~OffloadingVideoDecoder() override;
// VideoDecoder implementation.
+ VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
diff --git a/chromium/media/filters/offloading_video_decoder_unittest.cc b/chromium/media/filters/offloading_video_decoder_unittest.cc
index 29813ad3120..b6d2abf4971 100644
--- a/chromium/media/filters/offloading_video_decoder_unittest.cc
+++ b/chromium/media/filters/offloading_video_decoder_unittest.cc
@@ -39,6 +39,11 @@ class MockOffloadableVideoDecoder : public OffloadableVideoDecoder {
std::string GetDisplayName() const override {
return "MockOffloadableVideoDecoder";
}
+
+ VideoDecoderType GetDecoderType() const override {
+ return VideoDecoderType::kUnknown;
+ }
+
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
diff --git a/chromium/media/filters/pipeline_controller.cc b/chromium/media/filters/pipeline_controller.cc
index 97e430651a7..68b39ebe31a 100644
--- a/chromium/media/filters/pipeline_controller.cc
+++ b/chromium/media/filters/pipeline_controller.cc
@@ -393,6 +393,10 @@ void PipelineController::SetPreservesPitch(bool preserves_pitch) {
pipeline_->SetPreservesPitch(preserves_pitch);
}
+void PipelineController::SetAutoplayInitiated(bool autoplay_initiated) {
+ pipeline_->SetAutoplayInitiated(autoplay_initiated);
+}
+
base::TimeDelta PipelineController::GetMediaTime() const {
return pipeline_->GetMediaTime();
}
diff --git a/chromium/media/filters/pipeline_controller.h b/chromium/media/filters/pipeline_controller.h
index 08db9dcf214..a77ab00085b 100644
--- a/chromium/media/filters/pipeline_controller.h
+++ b/chromium/media/filters/pipeline_controller.h
@@ -133,6 +133,7 @@ class MEDIA_EXPORT PipelineController {
void SetVolume(float volume);
void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint);
void SetPreservesPitch(bool preserves_pitch);
+ void SetAutoplayInitiated(bool autoplay_initiated);
base::TimeDelta GetMediaTime() const;
Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
base::TimeDelta GetMediaDuration() const;
diff --git a/chromium/media/filters/pipeline_controller_unittest.cc b/chromium/media/filters/pipeline_controller_unittest.cc
index 0bced42367d..390dbc69409 100644
--- a/chromium/media/filters/pipeline_controller_unittest.cc
+++ b/chromium/media/filters/pipeline_controller_unittest.cc
@@ -152,8 +152,8 @@ class PipelineControllerTest : public ::testing::Test, public Pipeline::Client {
void OnVideoOpacityChange(bool opaque) override {}
void OnVideoFrameRateChange(base::Optional<int>) override {}
void OnVideoAverageKeyframeDistanceUpdate() override {}
- void OnAudioDecoderChange(const PipelineDecoderInfo& info) override {}
- void OnVideoDecoderChange(const PipelineDecoderInfo& info) override {}
+ void OnAudioDecoderChange(const AudioDecoderInfo& info) override {}
+ void OnVideoDecoderChange(const VideoDecoderInfo& info) override {}
base::test::SingleThreadTaskEnvironment task_environment_;
diff --git a/chromium/media/filters/source_buffer_state.cc b/chromium/media/filters/source_buffer_state.cc
index 9ce7a5934b6..3b4c9e16f79 100644
--- a/chromium/media/filters/source_buffer_state.cc
+++ b/chromium/media/filters/source_buffer_state.cc
@@ -16,6 +16,7 @@
#include "media/filters/chunk_demuxer.h"
#include "media/filters/frame_processor.h"
#include "media/filters/source_buffer_stream.h"
+#include "media/media_buildflags.h"
namespace media {
@@ -214,8 +215,8 @@ bool SourceBufferState::Append(const uint8_t* data,
append_window_end_during_append_ = append_window_end;
timestamp_offset_during_append_ = timestamp_offset;
- // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with
- // append window and timestamp offset pointer. See http://crbug.com/351454.
+ // TODO(wolenetz): Curry and pass a NewBuffersCB here bound with append window
+ // and timestamp offset pointer. See http://crbug.com/351454.
bool result = stream_parser_->Parse(data, length);
if (!result) {
MEDIA_LOG(ERROR, media_log_)
@@ -229,6 +230,31 @@ bool SourceBufferState::Append(const uint8_t* data,
return result;
}
+bool SourceBufferState::AppendChunks(
+ std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
+ TimeDelta append_window_start,
+ TimeDelta append_window_end,
+ TimeDelta* timestamp_offset) {
+ append_in_progress_ = true;
+ DCHECK(timestamp_offset);
+ DCHECK(!timestamp_offset_during_append_);
+ append_window_start_during_append_ = append_window_start;
+ append_window_end_during_append_ = append_window_end;
+ timestamp_offset_during_append_ = timestamp_offset;
+
+ // TODO(wolenetz): Curry and pass a NewBuffersCB here bound with append window
+ // and timestamp offset pointer. See http://crbug.com/351454.
+ bool result = stream_parser_->ProcessChunks(std::move(buffer_queue));
+ if (!result) {
+ MEDIA_LOG(ERROR, media_log_)
+ << __func__ << ": Processing encoded chunks for buffering failed.";
+ }
+
+ timestamp_offset_during_append_ = nullptr;
+ append_in_progress_ = false;
+ return result;
+}
+
void SourceBufferState::ResetParserState(TimeDelta append_window_start,
TimeDelta append_window_end,
base::TimeDelta* timestamp_offset) {
@@ -689,6 +715,31 @@ bool SourceBufferState::OnNewConfigs(
<< " config: " << video_config.AsHumanReadableString();
DCHECK(video_config.IsValidConfig());
+ if (video_config.codec() == kCodecHEVC) {
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+ // On ChromeOS, HEVC is only supported through EME, so require the
+ // config to be for an encrypted track if on ChromeOS. Even so,
+ // conditionally allow clear HEVC on ChromeOS if cmdline has test
+ // override.
+ if (video_config.encryption_scheme() ==
+ EncryptionScheme::kUnencrypted &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClearHevcForTesting)) {
+ MEDIA_LOG(ERROR, media_log_)
+ << "MSE playback of HEVC on ChromeOS is only supported via "
+ "platform decryptor, but the provided HEVC track is not "
+ "encrypted.";
+ return false;
+ }
+#endif // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+#else
+ NOTREACHED()
+ << "MSE parser must not emit HEVC tracks on build configurations "
+ "that do not support HEVC playback via platform.";
+#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+ }
+
const auto& it = std::find(expected_vcodecs.begin(),
expected_vcodecs.end(), video_config.codec());
if (it == expected_vcodecs.end()) {
diff --git a/chromium/media/filters/source_buffer_state.h b/chromium/media/filters/source_buffer_state.h
index ae4c76abbc2..fdf6be2f9c8 100644
--- a/chromium/media/filters/source_buffer_state.h
+++ b/chromium/media/filters/source_buffer_state.h
@@ -62,11 +62,16 @@ class MEDIA_EXPORT SourceBufferState {
// append. |append_window_start| and |append_window_end| correspond to the MSE
// spec's similarly named source buffer attributes that are used in coded
// frame processing.
+ // AppendChunks appends the provided BufferQueue.
bool Append(const uint8_t* data,
size_t length,
TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset);
+ bool AppendChunks(std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
+ TimeDelta append_window_start,
+ TimeDelta append_window_end,
+ TimeDelta* timestamp_offset);
// Aborts the current append sequence and resets the parser.
void ResetParserState(TimeDelta append_window_start,
diff --git a/chromium/media/filters/stream_parser_factory.cc b/chromium/media/filters/stream_parser_factory.cc
index 126c1814a16..29fb715ec7e 100644
--- a/chromium/media/filters/stream_parser_factory.cc
+++ b/chromium/media/filters/stream_parser_factory.cc
@@ -14,13 +14,16 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
+#include "media/base/audio_decoder_config.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/video_codecs.h"
+#include "media/base/video_decoder_config.h"
#include "media/formats/mp4/mp4_stream_parser.h"
#include "media/formats/mpeg/adts_stream_parser.h"
#include "media/formats/mpeg/mpeg1_audio_stream_parser.h"
+#include "media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h"
#include "media/formats/webm/webm_stream_parser.h"
#include "media/media_buildflags.h"
@@ -517,6 +520,7 @@ static SupportsType CheckTypeAndCodecs(
return IsNotSupported;
}
+// static
SupportsType StreamParserFactory::IsTypeSupported(
const std::string& type,
const std::vector<std::string>& codecs) {
@@ -526,6 +530,7 @@ SupportsType StreamParserFactory::IsTypeSupported(
nullptr);
}
+// static
std::unique_ptr<StreamParser> StreamParserFactory::Create(
const std::string& type,
const std::vector<std::string>& codecs,
@@ -535,18 +540,19 @@ std::unique_ptr<StreamParser> StreamParserFactory::Create(
std::vector<CodecInfo::HistogramTag> audio_codecs;
std::vector<CodecInfo::HistogramTag> video_codecs;
- if (IsSupported == CheckTypeAndCodecs(type, codecs, media_log,
- &factory_function, &audio_codecs,
- &video_codecs)) {
+ // TODO(crbug.com/535738): Relax the requirement for specific codecs (allow
+ // MayBeSupported here), and relocate the logging to the parser configuration
+ // callback. This creation method is called in AddId(), and also in
+ // CanChangeType() and ChangeType(), so potentially overlogs codecs leading to
+ // disproportion versus actually parsed codec configurations from
+ // initialization segments. For this work and also recording when implicit
+ // codec switching occurs (without explicit ChangeType), see
+ // https://crbug.com/535738.
+ SupportsType supportsType = CheckTypeAndCodecs(
+ type, codecs, media_log, &factory_function, &audio_codecs, &video_codecs);
+
+ if (IsSupported == supportsType) {
// Log the expected codecs.
- // TODO(wolenetz): Relax the requirement for specific codecs (allow
- // MayBeSupported here), and relocate the logging to the parser
- // configuration callback. This creation method is called in AddId(), and
- // also in CanChangeType() and ChangeType(), so potentially overlogs codecs
- // leading to disproportion versus actually parsed codec configurations from
- // initialization segments. For this work and also recording when implicit
- // codec switching occurs (without explicit ChangeType), see
- // https://crbug.com/535738.
for (size_t i = 0; i < audio_codecs.size(); ++i) {
UMA_HISTOGRAM_ENUMERATION("Media.MSE.AudioCodec", audio_codecs[i],
CodecInfo::HISTOGRAM_MAX + 1);
@@ -569,4 +575,28 @@ std::unique_ptr<StreamParser> StreamParserFactory::Create(
return stream_parser;
}
+// static
+std::unique_ptr<StreamParser> StreamParserFactory::Create(
+ std::unique_ptr<AudioDecoderConfig> audio_config) {
+ DCHECK(audio_config);
+
+ // TODO(crbug.com/1144908): Histogram-log the codec used for buffering
+ // WebCodecs in MSE?
+
+ return std::make_unique<media::WebCodecsEncodedChunkStreamParser>(
+ std::move(audio_config));
+}
+
+// static
+std::unique_ptr<StreamParser> StreamParserFactory::Create(
+ std::unique_ptr<VideoDecoderConfig> video_config) {
+ DCHECK(video_config);
+
+ // TODO(crbug.com/1144908): Histogram-log the codec used for buffering
+ // WebCodecs in MSE?
+
+ return std::make_unique<media::WebCodecsEncodedChunkStreamParser>(
+ std::move(video_config));
+}
+
} // namespace media
diff --git a/chromium/media/filters/stream_parser_factory.h b/chromium/media/filters/stream_parser_factory.h
index 50544a5a93e..0f28977ab73 100644
--- a/chromium/media/filters/stream_parser_factory.h
+++ b/chromium/media/filters/stream_parser_factory.h
@@ -15,7 +15,9 @@
namespace media {
+class AudioDecoderConfig;
class StreamParser;
+class VideoDecoderConfig;
class MEDIA_EXPORT StreamParserFactory {
public:
@@ -36,10 +38,28 @@ class MEDIA_EXPORT StreamParserFactory {
// Returns a new StreamParser object if |type| and all codecs listed in
// |codecs| are supported.
// Returns NULL otherwise.
+ // The |audio_config| and |video_config| overloads behave similarly, except
+ // the caller must provide a valid, supported decoder config; those overloads'
+ // usage indicates that we intend to buffer WebCodecs encoded audio or video
+ // chunks with this parser's ProcessChunks() method. Note that
+ // these overloads do not check support, unlike the |type| and |codecs|
+ // version. Support checking for WebCodecs-originated decoder configs could be
+ // async, and should be done by the caller if necessary as part of the decoder
+ // config creation rather than relying upon parser creation to do this
+ // potentially expensive step (this step is typically done in a synchronous
+ // API call by the web app, such as addSourceBuffer().) Like |type| and
+ // |codecs| versions, basic IsValidConfig() is done on configs emitted from
+ // the parser. Failing that catching an unsupported config, eventual pipeline
+ // error should occur for unsupported or invalid decoder configs during
+ // attempted decode.
static std::unique_ptr<StreamParser> Create(
const std::string& type,
const std::vector<std::string>& codecs,
MediaLog* media_log);
+ static std::unique_ptr<StreamParser> Create(
+ std::unique_ptr<AudioDecoderConfig> audio_config);
+ static std::unique_ptr<StreamParser> Create(
+ std::unique_ptr<VideoDecoderConfig> video_config);
};
} // namespace media
diff --git a/chromium/media/filters/video_decoder_stream_unittest.cc b/chromium/media/filters/video_decoder_stream_unittest.cc
index 75d0f304c78..9293b3b772e 100644
--- a/chromium/media/filters/video_decoder_stream_unittest.cc
+++ b/chromium/media/filters/video_decoder_stream_unittest.cc
@@ -11,6 +11,7 @@
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "media/base/fake_demuxer_stream.h"
@@ -100,11 +101,10 @@ class VideoDecoderStreamTest
base::BindRepeating(&VideoDecoderStreamTest::CreateVideoDecodersForTest,
base::Unretained(this)),
&media_log_));
- video_decoder_stream_->set_decoder_change_observer_for_testing(
- base::BindRepeating(&VideoDecoderStreamTest::OnDecoderChanged,
- base::Unretained(this)));
+ video_decoder_stream_->set_decoder_change_observer(base::BindRepeating(
+ &VideoDecoderStreamTest::OnDecoderChanged, base::Unretained(this)));
video_decoder_stream_
- ->GetDecoderSelectorForTesting(util::PassKey<VideoDecoderStreamTest>())
+ ->GetDecoderSelectorForTesting(base::PassKey<VideoDecoderStreamTest>())
.OverrideDecoderPriorityCBForTesting(
base::BindRepeating(MockDecoderPriority));
if (GetParam().has_prepare) {
@@ -354,14 +354,15 @@ class VideoDecoderStreamTest
}
// Callback for VideoDecoderStream::Read().
- void FrameReady(VideoDecoderStream::ReadStatus status,
- scoped_refptr<VideoFrame> frame) {
+ void FrameReady(VideoDecoderStream::ReadResult result) {
DCHECK(pending_read_);
+ last_read_status_code_ = result.code();
+ scoped_refptr<VideoFrame> frame = last_read_status_code_ == StatusCode::kOk
+ ? std::move(result).value()
+ : nullptr;
frame_read_ = frame;
- last_read_status_ = status;
- if (frame && !frame->metadata()->end_of_stream) {
- EXPECT_EQ(*frame->metadata()->frame_duration,
- demuxer_stream_->duration());
+ if (frame && !frame->metadata().end_of_stream) {
+ EXPECT_EQ(*frame->metadata().frame_duration, demuxer_stream_->duration());
num_decoded_frames_++;
}
@@ -391,7 +392,7 @@ class VideoDecoderStreamTest
void ReadAllFrames(int expected_decoded_frames) {
do {
ReadOneFrame();
- } while (frame_read_.get() && !frame_read_->metadata()->end_of_stream);
+ } while (frame_read_.get() && !frame_read_->metadata().end_of_stream);
DCHECK_EQ(expected_decoded_frames, num_decoded_frames_);
}
@@ -541,7 +542,7 @@ class VideoDecoderStreamTest
bool pending_stop_;
int num_decoded_bytes_unreported_;
scoped_refptr<VideoFrame> frame_read_;
- VideoDecoderStream::ReadStatus last_read_status_;
+ StatusCode last_read_status_code_;
// Decryptor has no key to decrypt a frame.
bool has_no_key_;
@@ -692,17 +693,17 @@ TEST_P(VideoDecoderStreamTest, Read_ProperMetadata) {
EXPECT_TRUE(frame_read_);
- auto* metadata = frame_read_->metadata();
+ const VideoFrameMetadata& metadata = frame_read_->metadata();
// Verify the decoding metadata is accurate.
- EXPECT_EQ(*metadata->decode_end_time - *metadata->decode_begin_time,
+ EXPECT_EQ(*metadata.decode_end_time - *metadata.decode_begin_time,
kDecodeDelay);
// Verify the processing metadata is accurate.
const base::TimeDelta expected_processing_time =
GetParam().has_prepare ? (kDecodeDelay + kPrepareDelay) : kDecodeDelay;
- EXPECT_EQ(*metadata->processing_time, expected_processing_time);
+ EXPECT_EQ(*metadata.processing_time, expected_processing_time);
}
TEST_P(VideoDecoderStreamTest, Read_BlockedDemuxer) {
@@ -815,11 +816,11 @@ TEST_P(VideoDecoderStreamTest, Read_DuringEndOfStreamDecode) {
decoder_->SatisfySingleDecode();
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_, VideoDecoderStream::OK);
+ EXPECT_EQ(last_read_status_code_, StatusCode::kOk);
// The read output should indicate end of stream.
ASSERT_TRUE(frame_read_.get());
- EXPECT_TRUE(frame_read_->metadata()->end_of_stream);
+ EXPECT_TRUE(frame_read_->metadata().end_of_stream);
}
TEST_P(VideoDecoderStreamTest, Read_DemuxerStreamReadError) {
@@ -838,7 +839,8 @@ TEST_P(VideoDecoderStreamTest, Read_DemuxerStreamReadError) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_, VideoDecoderStream::DECODE_ERROR);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
// No Reset() before initialization is successfully completed.
@@ -1026,7 +1028,7 @@ TEST_P(VideoDecoderStreamTest, FallbackDecoder_DecodeError) {
ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName());
ASSERT_FALSE(pending_read_);
- ASSERT_EQ(VideoDecoderStream::OK, last_read_status_);
+ ASSERT_EQ(last_read_status_code_, StatusCode::kOk);
// Check that we fell back to Decoder2.
ASSERT_GT(decoder_->total_bytes_decoded(), 0);
@@ -1066,15 +1068,15 @@ TEST_P(VideoDecoderStreamTest,
// A frame should have been emitted.
EXPECT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_, VideoDecoderStream::OK);
- EXPECT_FALSE(frame_read_->metadata()->end_of_stream);
+ EXPECT_EQ(last_read_status_code_, StatusCode::kOk);
+ EXPECT_FALSE(frame_read_->metadata().end_of_stream);
EXPECT_GT(decoder_->total_bytes_decoded(), 0);
ReadOneFrame();
EXPECT_FALSE(pending_read_);
EXPECT_EQ(0, video_decoder_stream_->get_fallback_buffers_size_for_testing());
- EXPECT_TRUE(frame_read_->metadata()->end_of_stream);
+ EXPECT_TRUE(frame_read_->metadata().end_of_stream);
}
TEST_P(VideoDecoderStreamTest,
@@ -1140,7 +1142,8 @@ TEST_P(VideoDecoderStreamTest, FallbackDecoder_DecodeErrorRepeated) {
// No decoders left, expect failure.
EXPECT_EQ(decoder_, nullptr);
EXPECT_FALSE(pending_read_);
- EXPECT_EQ(VideoDecoderStream::DECODE_ERROR, last_read_status_);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
// This tests verifies that we properly fallback to a new decoder if the first
@@ -1161,7 +1164,7 @@ TEST_P(VideoDecoderStreamTest,
// Verify that the first frame was decoded successfully.
EXPECT_FALSE(pending_read_);
EXPECT_GT(decoder_->total_bytes_decoded(), 0);
- EXPECT_EQ(VideoDecoderStream::OK, last_read_status_);
+ EXPECT_EQ(last_read_status_code_, StatusCode::kOk);
// Continue up to the point of reinitialization.
EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
@@ -1185,7 +1188,7 @@ TEST_P(VideoDecoderStreamTest,
// Verify that fallback happened.
EXPECT_EQ(GetDecoderName(0), decoder_->GetDisplayName());
EXPECT_FALSE(pending_read_);
- EXPECT_EQ(VideoDecoderStream::OK, last_read_status_);
+ EXPECT_EQ(last_read_status_code_, StatusCode::kOk);
EXPECT_GT(decoder_->total_bytes_decoded(), 0);
}
@@ -1222,7 +1225,8 @@ TEST_P(VideoDecoderStreamTest,
// No decoders left.
EXPECT_EQ(decoder_, nullptr);
EXPECT_FALSE(pending_read_);
- EXPECT_EQ(VideoDecoderStream::DECODE_ERROR, last_read_status_);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
TEST_P(VideoDecoderStreamTest,
@@ -1375,7 +1379,7 @@ TEST_P(VideoDecoderStreamTest, FallbackDecoder_SelectedOnDecodeThenInitErrors) {
ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName());
ASSERT_FALSE(pending_read_);
- ASSERT_EQ(VideoDecoderStream::OK, last_read_status_);
+ ASSERT_EQ(last_read_status_code_, StatusCode::kOk);
// Can't check previously selected decoder(s) right now, they might have been
// destroyed already.
@@ -1400,7 +1404,7 @@ TEST_P(VideoDecoderStreamTest, FallbackDecoder_SelectedOnInitThenDecodeErrors) {
ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName());
ASSERT_FALSE(pending_read_);
- ASSERT_EQ(VideoDecoderStream::OK, last_read_status_);
+ ASSERT_EQ(last_read_status_code_, StatusCode::kOk);
// Can't check previously selected decoder(s) right now, they might have been
// destroyed already.
@@ -1422,7 +1426,7 @@ TEST_P(VideoDecoderStreamTest,
decoder_->SimulateError();
// The error must surface from Read() as DECODE_ERROR.
- while (last_read_status_ == VideoDecoderStream::OK) {
+ while (last_read_status_code_ == StatusCode::kOk) {
ReadOneFrame();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(pending_read_);
@@ -1431,7 +1435,8 @@ TEST_P(VideoDecoderStreamTest,
// Verify the error was surfaced, rather than falling back to other decoders.
ASSERT_EQ(GetDecoderName(0), decoder_->GetDisplayName());
EXPECT_FALSE(pending_read_);
- ASSERT_EQ(VideoDecoderStream::DECODE_ERROR, last_read_status_);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
TEST_P(VideoDecoderStreamTest, DecoderErrorWhenNotReading) {
@@ -1450,12 +1455,13 @@ TEST_P(VideoDecoderStreamTest, DecoderErrorWhenNotReading) {
decoder_->SimulateError();
// The error must surface from Read() as DECODE_ERROR.
- while (last_read_status_ == VideoDecoderStream::OK) {
+ while (last_read_status_code_ == StatusCode::kOk) {
ReadOneFrame();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(pending_read_);
}
- EXPECT_EQ(VideoDecoderStream::DECODE_ERROR, last_read_status_);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
TEST_P(VideoDecoderStreamTest, ReinitializeFailure_Once) {
@@ -1516,12 +1522,13 @@ TEST_P(VideoDecoderStreamTest, ReinitializeFailure_NoSupportedDecoder) {
ReadUntilDecoderReinitialized();
// The error will surface from Read() as DECODE_ERROR.
- while (last_read_status_ == VideoDecoderStream::OK) {
+ while (last_read_status_code_ == StatusCode::kOk) {
ReadOneFrame();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(pending_read_);
}
- EXPECT_EQ(VideoDecoderStream::DECODE_ERROR, last_read_status_);
+ EXPECT_NE(last_read_status_code_, StatusCode::kOk);
+ EXPECT_NE(last_read_status_code_, StatusCode::kAborted);
}
TEST_P(VideoDecoderStreamTest, Destroy_DuringFallbackDecoderSelection) {
diff --git a/chromium/media/filters/video_renderer_algorithm.cc b/chromium/media/filters/video_renderer_algorithm.cc
index 0cef397855b..863359fd01a 100644
--- a/chromium/media/filters/video_renderer_algorithm.cc
+++ b/chromium/media/filters/video_renderer_algorithm.cc
@@ -327,12 +327,12 @@ int64_t VideoRendererAlgorithm::GetMemoryUsage() const {
void VideoRendererAlgorithm::EnqueueFrame(scoped_refptr<VideoFrame> frame) {
DCHECK(frame);
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
// Note: Not all frames have duration. E.g., this class is used with WebRTC
// which does not provide duration information for its frames.
base::TimeDelta metadata_frame_duration =
- frame->metadata()->frame_duration.value_or(base::TimeDelta());
+ frame->metadata().frame_duration.value_or(base::TimeDelta());
auto timestamp = frame->timestamp();
ReadyFrame ready_frame(std::move(frame));
auto it = frame_queue_.empty()
@@ -399,7 +399,7 @@ void VideoRendererAlgorithm::EnqueueFrame(scoped_refptr<VideoFrame> frame) {
wallclock_duration = ready_frame.end_time - ready_frame.start_time;
}
- ready_frame.frame->metadata()->wallclock_frame_duration = wallclock_duration;
+ ready_frame.frame->metadata().wallclock_frame_duration = wallclock_duration;
// The vast majority of cases should always append to the back, but in rare
// circumstance we get out of order timestamps, http://crbug.com/386551.
@@ -481,7 +481,7 @@ void VideoRendererAlgorithm::UpdateFrameStatistics() {
{
const auto& last_frame = frame_queue_.back().frame;
base::TimeDelta metadata_frame_duration =
- last_frame->metadata()->frame_duration.value_or(base::TimeDelta());
+ last_frame->metadata().frame_duration.value_or(base::TimeDelta());
if (metadata_frame_duration > base::TimeDelta()) {
have_metadata_duration = true;
media_timestamps.push_back(last_frame->timestamp() +
diff --git a/chromium/media/filters/video_renderer_algorithm_unittest.cc b/chromium/media/filters/video_renderer_algorithm_unittest.cc
index b3e7b5b9d99..a1511eda89d 100644
--- a/chromium/media/filters/video_renderer_algorithm_unittest.cc
+++ b/chromium/media/filters/video_renderer_algorithm_unittest.cc
@@ -1212,7 +1212,7 @@ TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFramesWithoutRendering) {
// as effective since we know the duration of it. It is not removed since we
// only have one frame in the queue though.
auto frame = CreateFrame(tg.interval(0));
- frame->metadata()->frame_duration = tg.interval(1);
+ frame->metadata().frame_duration = tg.interval(1);
algorithm_.EnqueueFrame(frame);
ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current() + tg.interval(3)));
EXPECT_EQ(0u, EffectiveFramesQueued());
@@ -1623,7 +1623,7 @@ TEST_F(VideoRendererAlgorithmTest, InfiniteDurationMetadata) {
TickGenerator tg(tick_clock_->NowTicks(), 50);
auto frame = CreateFrame(kInfiniteDuration);
- frame->metadata()->frame_duration = tg.interval(1);
+ frame->metadata().frame_duration = tg.interval(1);
algorithm_.EnqueueFrame(frame);
// This should not crash or fail.
@@ -1636,7 +1636,7 @@ TEST_F(VideoRendererAlgorithmTest, UsesFrameDuration) {
TickGenerator tg(tick_clock_->NowTicks(), 50);
auto frame = CreateFrame(tg.interval(0));
- frame->metadata()->frame_duration = tg.interval(1);
+ frame->metadata().frame_duration = tg.interval(1);
algorithm_.EnqueueFrame(frame);
// This should not crash or fail.
@@ -1648,7 +1648,7 @@ TEST_F(VideoRendererAlgorithmTest, UsesFrameDuration) {
constexpr base::TimeDelta kLongDuration = base::TimeDelta::FromSeconds(3);
for (int i = 1; i < 4; ++i) {
frame = CreateFrame(tg.interval(i));
- frame->metadata()->frame_duration = i == 3 ? kLongDuration : tg.interval(1);
+ frame->metadata().frame_duration = i == 3 ? kLongDuration : tg.interval(1);
algorithm_.EnqueueFrame(frame);
}
@@ -1670,7 +1670,7 @@ TEST_F(VideoRendererAlgorithmTest, WallClockDurationMetadataSet) {
for (int i = 0; i < frame_count; i++) {
auto frame = CreateFrame(tg.interval(i));
- frame->metadata()->frame_duration = tg.interval(1);
+ frame->metadata().frame_duration = tg.interval(1);
algorithm_.EnqueueFrame(frame);
}
@@ -1680,7 +1680,7 @@ TEST_F(VideoRendererAlgorithmTest, WallClockDurationMetadataSet) {
SCOPED_TRACE(base::StringPrintf("Frame #%d", i));
- EXPECT_EQ(*frame->metadata()->wallclock_frame_duration, intended_duration);
+ EXPECT_EQ(*frame->metadata().wallclock_frame_duration, intended_duration);
EXPECT_EQ(algorithm_.average_frame_duration(), intended_duration);
}
}
diff --git a/chromium/media/filters/vp9_parser.h b/chromium/media/filters/vp9_parser.h
index 4f360385062..f85b5217836 100644
--- a/chromium/media/filters/vp9_parser.h
+++ b/chromium/media/filters/vp9_parser.h
@@ -300,7 +300,7 @@ class MEDIA_EXPORT Vp9Parser {
// The parsing context that persists across frames.
class Context {
public:
- class Vp9FrameContextManager {
+ class MEDIA_EXPORT Vp9FrameContextManager {
public:
Vp9FrameContextManager();
~Vp9FrameContextManager();
diff --git a/chromium/media/filters/vp9_uncompressed_header_parser.cc b/chromium/media/filters/vp9_uncompressed_header_parser.cc
index 6c99ef5b468..294c709ae57 100644
--- a/chromium/media/filters/vp9_uncompressed_header_parser.cc
+++ b/chromium/media/filters/vp9_uncompressed_header_parser.cc
@@ -622,6 +622,11 @@ Vp9UncompressedHeaderParser::Vp9UncompressedHeaderParser(
Vp9Parser::Context* context)
: context_(context) {}
+const Vp9FrameContext&
+Vp9UncompressedHeaderParser::GetVp9DefaultFrameContextForTesting() const {
+ return kVp9DefaultFrameContext;
+}
+
uint8_t Vp9UncompressedHeaderParser::ReadProfile() {
uint8_t profile = 0;
@@ -765,6 +770,8 @@ Vp9InterpolationFilter Vp9UncompressedHeaderParser::ReadInterpolationFilter() {
void Vp9UncompressedHeaderParser::SetupPastIndependence(Vp9FrameHeader* fhdr) {
memset(&context_->segmentation_, 0, sizeof(context_->segmentation_));
+ memset(fhdr->ref_frame_sign_bias, 0, sizeof(fhdr->ref_frame_sign_bias));
+
ResetLoopfilter();
fhdr->frame_context = kVp9DefaultFrameContext;
DCHECK(fhdr->frame_context.IsValid());
@@ -1069,7 +1076,7 @@ bool Vp9UncompressedHeaderParser::Parse(const uint8_t* stream,
fhdr->frame_context_idx_to_save_probs = fhdr->frame_context_idx =
reader_.ReadLiteral(kVp9NumFrameContextsLog2);
- if (fhdr->IsIntra()) {
+ if (fhdr->IsIntra() || fhdr->error_resilient_mode) {
SetupPastIndependence(fhdr);
if (fhdr->IsKeyframe() || fhdr->error_resilient_mode ||
fhdr->reset_frame_context == 3) {
diff --git a/chromium/media/filters/vp9_uncompressed_header_parser.h b/chromium/media/filters/vp9_uncompressed_header_parser.h
index ea85af4769b..1cf5a408eb3 100644
--- a/chromium/media/filters/vp9_uncompressed_header_parser.h
+++ b/chromium/media/filters/vp9_uncompressed_header_parser.h
@@ -8,9 +8,11 @@
#include "media/filters/vp9_parser.h"
#include "media/filters/vp9_raw_bits_reader.h"
+#include "media/base/media_export.h"
+
namespace media {
-class Vp9UncompressedHeaderParser {
+class MEDIA_EXPORT Vp9UncompressedHeaderParser {
public:
Vp9UncompressedHeaderParser(Vp9Parser::Context* context);
@@ -18,7 +20,11 @@ class Vp9UncompressedHeaderParser {
// Returns true if no error.
bool Parse(const uint8_t* stream, off_t frame_size, Vp9FrameHeader* fhdr);
+ const Vp9FrameContext& GetVp9DefaultFrameContextForTesting() const;
+
private:
+ friend class Vp9UncompressedHeaderParserTest;
+
uint8_t ReadProfile();
bool VerifySyncCode();
bool ReadColorConfig(Vp9FrameHeader* fhdr);
diff --git a/chromium/media/filters/vp9_uncompressed_header_parser_unittest.cc b/chromium/media/filters/vp9_uncompressed_header_parser_unittest.cc
new file mode 100644
index 00000000000..53fbfafe261
--- /dev/null
+++ b/chromium/media/filters/vp9_uncompressed_header_parser_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/filters/vp9_uncompressed_header_parser.h"
+
+#include "media/filters/vp9_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class Vp9UncompressedHeaderParserTest : public testing::Test {
+ public:
+ void SetupPastIndependence(Vp9FrameHeader* fhdr) {
+ vp9_uncompressed_header_parser_.SetupPastIndependence(fhdr);
+ }
+
+ const Vp9FrameContext& GetVp9DefaultFrameContextForTesting() const {
+ return vp9_uncompressed_header_parser_
+ .GetVp9DefaultFrameContextForTesting();
+ }
+
+ Vp9UncompressedHeaderParserTest()
+ : vp9_uncompressed_header_parser_((&vp9_parser_context_)) {}
+
+ protected:
+ const Vp9LoopFilterParams& GetLoopFilter() const {
+ return vp9_parser_context_.loop_filter();
+ }
+
+ Vp9Parser::Context vp9_parser_context_;
+ Vp9UncompressedHeaderParser vp9_uncompressed_header_parser_;
+};
+
+TEST_F(Vp9UncompressedHeaderParserTest, SetupPastIndependence) {
+ Vp9FrameHeader frame_header = {};
+
+ SetupPastIndependence(&frame_header);
+
+ EXPECT_EQ(0, frame_header.ref_frame_sign_bias[VP9_FRAME_INTRA]);
+ EXPECT_EQ(0, frame_header.ref_frame_sign_bias[VP9_FRAME_LAST]);
+ EXPECT_EQ(0, frame_header.ref_frame_sign_bias[VP9_FRAME_GOLDEN]);
+ EXPECT_EQ(0, frame_header.ref_frame_sign_bias[VP9_FRAME_ALTREF]);
+
+ // Verify ResetLoopfilter() result
+ const Vp9LoopFilterParams& lf = GetLoopFilter();
+ EXPECT_TRUE(lf.delta_enabled);
+ EXPECT_TRUE(lf.delta_update);
+ EXPECT_EQ(1, lf.ref_deltas[VP9_FRAME_INTRA]);
+ EXPECT_EQ(0, lf.ref_deltas[VP9_FRAME_LAST]);
+ EXPECT_EQ(-1, lf.ref_deltas[VP9_FRAME_GOLDEN]);
+ EXPECT_EQ(-1, lf.ref_deltas[VP9_FRAME_ALTREF]);
+ EXPECT_EQ(0, lf.mode_deltas[0]);
+ EXPECT_EQ(0, lf.mode_deltas[1]);
+
+ EXPECT_TRUE(frame_header.frame_context.IsValid());
+
+ static_assert(std::is_pod<Vp9FrameContext>::value,
+ "Vp9FrameContext is not POD, rewrite the next EXPECT_TRUE");
+ EXPECT_TRUE(std::memcmp(&frame_header.frame_context,
+ &GetVp9DefaultFrameContextForTesting(),
+ sizeof(GetVp9DefaultFrameContextForTesting())) == 0);
+}
+
+} // namespace media
diff --git a/chromium/media/filters/vpx_video_decoder.cc b/chromium/media/filters/vpx_video_decoder.cc
index 7cac1f7fe78..3351761ff07 100644
--- a/chromium/media/filters/vpx_video_decoder.cc
+++ b/chromium/media/filters/vpx_video_decoder.cc
@@ -98,6 +98,25 @@ static int32_t ReleaseVP9FrameBuffer(void* user_priv,
return 0;
}
+// static
+SupportedVideoDecoderConfigs VpxVideoDecoder::SupportedConfigs() {
+ SupportedVideoDecoderConfigs supported_configs;
+ supported_configs.emplace_back(/*profile_min=*/VP8PROFILE_ANY,
+ /*profile_max=*/VP8PROFILE_ANY,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false);
+
+ supported_configs.emplace_back(/*profile_min=*/VP9PROFILE_PROFILE0,
+ /*profile_max=*/VP9PROFILE_PROFILE2,
+ /*coded_size_min=*/kDefaultSwDecodeSizeMin,
+ /*coded_size_max=*/kDefaultSwDecodeSizeMax,
+ /*allow_encrypted=*/false,
+ /*require_encrypted=*/false);
+ return supported_configs;
+}
+
VpxVideoDecoder::VpxVideoDecoder(OffloadState offload_state)
: bind_callbacks_(offload_state == OffloadState::kNormal) {
DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -108,6 +127,10 @@ VpxVideoDecoder::~VpxVideoDecoder() {
CloseDecoder();
}
+VideoDecoderType VpxVideoDecoder::GetDecoderType() const {
+ return VideoDecoderType::kVpx;
+}
+
std::string VpxVideoDecoder::GetDisplayName() const {
return "VpxVideoDecoder";
}
@@ -182,7 +205,7 @@ void VpxVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
// We might get a successful VpxDecode but not a frame if only a partial
// decode happened.
if (video_frame) {
- video_frame->metadata()->power_efficient = false;
+ video_frame->metadata().power_efficient = false;
output_cb_.Run(video_frame);
}
@@ -338,6 +361,7 @@ bool VpxVideoDecoder::VpxDecode(const DecoderBuffer* buffer,
}
(*video_frame)->set_timestamp(buffer->timestamp());
+ (*video_frame)->set_hdr_metadata(config_.hdr_metadata());
// Prefer the color space from the config if available. It generally comes
// from the color tag which is more expressive than the vp8 and vp9 bitstream.
@@ -395,7 +419,6 @@ bool VpxVideoDecoder::VpxDecode(const DecoderBuffer* buffer,
(*video_frame)
->set_color_space(gfx::ColorSpace(primaries, transfer, matrix, range));
}
- (*video_frame)->set_hdr_metadata(config_.hdr_metadata());
return true;
}
diff --git a/chromium/media/filters/vpx_video_decoder.h b/chromium/media/filters/vpx_video_decoder.h
index 98eff915fe8..d4e5f74acb9 100644
--- a/chromium/media/filters/vpx_video_decoder.h
+++ b/chromium/media/filters/vpx_video_decoder.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
@@ -29,10 +30,13 @@ class FrameBufferPool;
// [1] http://wiki.webmproject.org/alpha-channel
class MEDIA_EXPORT VpxVideoDecoder : public OffloadableVideoDecoder {
public:
+ static SupportedVideoDecoderConfigs SupportedConfigs();
+
explicit VpxVideoDecoder(OffloadState offload_state = OffloadState::kNormal);
~VpxVideoDecoder() override;
// VideoDecoder implementation.
+ VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
diff --git a/chromium/media/filters/vpx_video_decoder_fuzzertest.cc b/chromium/media/filters/vpx_video_decoder_fuzzertest.cc
index 85cc43f6adc..087d46547e4 100644
--- a/chromium/media/filters/vpx_video_decoder_fuzzertest.cc
+++ b/chromium/media/filters/vpx_video_decoder_fuzzertest.cc
@@ -30,15 +30,15 @@ struct Env {
base::test::SingleThreadTaskEnvironment task_environment;
};
-void OnDecodeComplete(const base::Closure& quit_closure, media::Status status) {
- quit_closure.Run();
+void OnDecodeComplete(base::OnceClosure quit_closure, media::Status status) {
+ std::move(quit_closure).Run();
}
-void OnInitDone(const base::Closure& quit_closure,
+void OnInitDone(base::OnceClosure quit_closure,
bool* success_dest,
media::Status status) {
*success_dest = status.is_ok();
- quit_closure.Run();
+ std::move(quit_closure).Run();
}
void OnOutputComplete(scoped_refptr<media::VideoFrame> frame) {}
diff --git a/chromium/media/filters/vpx_video_decoder_unittest.cc b/chromium/media/filters/vpx_video_decoder_unittest.cc
index be6824bf297..0eab44301f2 100644
--- a/chromium/media/filters/vpx_video_decoder_unittest.cc
+++ b/chromium/media/filters/vpx_video_decoder_unittest.cc
@@ -160,7 +160,7 @@ class VpxVideoDecoderTest : public testing::Test {
}
void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
output_frames_.push_back(std::move(frame));
}